1/*-
2 * Copyright (c) 2005 Pawel Jakub Dawidek
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
--- 8 unchanged lines hidden (view full) ---
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: head/sys/crypto/via/padlock.c 160573 2006-07-22 13:14:11Z 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#if defined(__i386__) && !defined(PC98)
59#include <machine/cpufunc.h>
60#include <machine/cputypes.h>
61#include <machine/md_var.h>
62#include <machine/specialreg.h>
63#endif
64
65#include <opencrypto/cryptodev.h>
66#include <opencrypto/cryptosoft.h> /* for hmac_ipad_buffer and hmac_opad_buffer */
67#include <opencrypto/xform.h>
68#include <crypto/rijndael/rijndael.h>
69
70
71#define PADLOCK_ROUND_COUNT_AES128 10
72#define PADLOCK_ROUND_COUNT_AES192 12
73#define PADLOCK_ROUND_COUNT_AES256 14
74
75#define PADLOCK_ALGORITHM_TYPE_AES 0
76
77#define PADLOCK_KEY_GENERATION_HW 0
78#define PADLOCK_KEY_GENERATION_SW 1
79
80#define PADLOCK_DIRECTION_ENCRYPT 0
81#define PADLOCK_DIRECTION_DECRYPT 1
82
83#define PADLOCK_KEY_SIZE_128 0
84#define PADLOCK_KEY_SIZE_192 1
85#define PADLOCK_KEY_SIZE_256 2
86
87union padlock_cw {
88 uint64_t raw;
89 struct {
90 u_int round_count : 4;
91 u_int algorithm_type : 3;
92 u_int key_generation : 1;
93 u_int intermediate : 1;
94 u_int direction : 1;
95 u_int key_size : 2;
96 u_int filler0 : 20;
97 u_int filler1 : 32;
98 u_int filler2 : 32;
99 u_int filler3 : 32;
100 } __field;
101};
102#define cw_round_count __field.round_count
103#define cw_algorithm_type __field.algorithm_type
104#define cw_key_generation __field.key_generation
105#define cw_intermediate __field.intermediate
106#define cw_direction __field.direction
107#define cw_key_size __field.key_size
108#define cw_filler0 __field.filler0
109#define cw_filler1 __field.filler1
110#define cw_filler2 __field.filler2
111#define cw_filler3 __field.filler3
112
113struct padlock_session {
114 union padlock_cw ses_cw __aligned(16);
115 uint32_t ses_ekey[4 * (RIJNDAEL_MAXNR + 1) + 4] __aligned(16); /* 128 bit aligned */
116 uint32_t ses_dkey[4 * (RIJNDAEL_MAXNR + 1) + 4] __aligned(16); /* 128 bit aligned */
117 uint8_t ses_iv[16] __aligned(16); /* 128 bit aligned */
118 struct auth_hash *ses_axf;
119 uint8_t *ses_ictx;
120 uint8_t *ses_octx;
121 int ses_mlen;
122 int ses_used;
123 uint32_t ses_id;
124 TAILQ_ENTRY(padlock_session) ses_next;
125};
126
127struct padlock_softc {
128 int32_t sc_cid;
129 uint32_t sc_sid;
130 TAILQ_HEAD(, padlock_session) sc_sessions;
131 struct mtx sc_sessions_mtx;
132};
133
134static struct padlock_softc *padlock_sc;
135
136static int padlock_newsession(void *arg __unused, uint32_t *sidp,
137 struct cryptoini *cri);
138static int padlock_freesession(void *arg __unused, uint64_t tid);
139static int padlock_process(void *arg __unused, struct cryptop *crp,
140 int hint __unused);
141
142static __inline void
143padlock_cbc(void *in, void *out, size_t count, void *key, union padlock_cw *cw,
144 void *iv)
145{
146#ifdef __GNUCLIKE_ASM
147 /* The .byte line is really VIA C3 "xcrypt-cbc" instruction */
148 __asm __volatile(
149 "pushf \n\t"
150 "popf \n\t"
151 "rep \n\t"
152 ".byte 0x0f, 0xa7, 0xd0"
153 : "+a" (iv), "+c" (count), "+D" (out), "+S" (in)
154 : "b" (key), "d" (cw)
155 : "cc", "memory"
156 );
157#endif
158}
159
160static int
161padlock_init(void)
162{
163 struct padlock_softc *sc;
164#if defined(__i386__) && !defined(PC98)
165 if (!(via_feature_xcrypt & VIA_HAS_AES)) {
166 printf("PADLOCK: No ACE support.\n");
167 return (EINVAL);
168 } else
169 printf("PADLOCK: HW support loaded.\n");
170#else
171 return (EINVAL);
172#endif
173
174 padlock_sc = sc = malloc(sizeof(*padlock_sc), M_DEVBUF,
175 M_WAITOK | M_ZERO);
176 TAILQ_INIT(&sc->sc_sessions);
177 sc->sc_sid = 1;
178
179 sc->sc_cid = crypto_get_driverid(0);
180 if (sc->sc_cid < 0) {
181 printf("PADLOCK: Could not get crypto driver id.\n");
182 free(padlock_sc, M_DEVBUF);
183 padlock_sc = NULL;
184 return (ENOMEM);
185 }
186
187 mtx_init(&sc->sc_sessions_mtx, "padlock_mtx", NULL, MTX_DEF);
188 crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0, padlock_newsession,
189 padlock_freesession, padlock_process, NULL);
190 crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0, padlock_newsession,
--- 22 unchanged lines hidden (view full) ---
213 return (0);
214 mtx_lock(&sc->sc_sessions_mtx);
215 TAILQ_FOREACH(ses, &sc->sc_sessions, ses_next) {
216 if (ses->ses_used)
217 active++;
218 }
219 if (active > 0) {
220 mtx_unlock(&sc->sc_sessions_mtx);
221 printf("PADLOCK: Cannot destroy, %u sessions active.\n",
222 active);
223 return (EBUSY);
224 }
225 padlock_sc = NULL;
226 for (ses = TAILQ_FIRST(&sc->sc_sessions); ses != NULL;
227 ses = TAILQ_FIRST(&sc->sc_sessions)) {
228 TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
229 free(ses, M_DEVBUF);
230 }
231 mtx_destroy(&sc->sc_sessions_mtx);
232 crypto_unregister_all(sc->sc_cid);
233 free(sc, M_DEVBUF);
234 return (0);
235}
236
237static void
238padlock_setup_enckey(struct padlock_session *ses, caddr_t key, int klen)
239{
240 union padlock_cw *cw;
241 int i;
242
243 cw = &ses->ses_cw;
244 if (cw->cw_key_generation == PADLOCK_KEY_GENERATION_SW) {
245 /* Build expanded keys for both directions */
246 rijndaelKeySetupEnc(ses->ses_ekey, key, klen);
247 rijndaelKeySetupDec(ses->ses_dkey, key, klen);
248 for (i = 0; i < 4 * (RIJNDAEL_MAXNR + 1); i++) {
249 ses->ses_ekey[i] = ntohl(ses->ses_ekey[i]);
250 ses->ses_dkey[i] = ntohl(ses->ses_dkey[i]);
251 }
252 } else {
253 bcopy(key, ses->ses_ekey, klen);
254 bcopy(key, ses->ses_dkey, klen);
255 }
256}
257
258static void
259padlock_setup_mackey(struct padlock_session *ses, caddr_t key, int klen)
260{
261 struct auth_hash *axf;
262 int i;
263
264 klen /= 8;
265 axf = ses->ses_axf;
266
267 for (i = 0; i < klen; i++)
268 key[i] ^= HMAC_IPAD_VAL;
269
270 axf->Init(ses->ses_ictx);
271 axf->Update(ses->ses_ictx, key, klen);
272 axf->Update(ses->ses_ictx, hmac_ipad_buffer, axf->blocksize - klen);
273
274 for (i = 0; i < klen; i++)
275 key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
276
277 axf->Init(ses->ses_octx);
278 axf->Update(ses->ses_octx, key, klen);
279 axf->Update(ses->ses_octx, hmac_opad_buffer, axf->blocksize - klen);
280
281 for (i = 0; i < klen; i++)
282 key[i] ^= HMAC_OPAD_VAL;
283}
284
285/*
286 * Compute keyed-hash authenticator.
287 */
288static int
289padlock_authcompute(struct padlock_session *ses, struct cryptodesc *crd,
290 caddr_t buf, int flags)
291{
292 u_char hash[HASH_MAX_LEN];
293 struct auth_hash *axf;
294 union authctx ctx;
295 int error;
296
297 axf = ses->ses_axf;
298
299 bcopy(ses->ses_ictx, &ctx, axf->ctxsize);
300
301 error = crypto_apply(flags, buf, crd->crd_skip, crd->crd_len,
302 (int (*)(void *, void *, unsigned int))axf->Update, (caddr_t)&ctx);
303 if (error != 0)
304 return (error);
305
306 axf->Final(hash, &ctx);
307 bcopy(ses->ses_octx, &ctx, axf->ctxsize);
308 axf->Update(&ctx, hash, axf->hashsize);
309 axf->Final(hash, &ctx);
310
311 /* Inject the authentication data */
312 crypto_copyback(flags, buf, crd->crd_inject,
313 ses->ses_mlen == 0 ? axf->hashsize : ses->ses_mlen, hash);
314 return (0);
315}
316
317
318static int
319padlock_newsession(void *arg __unused, uint32_t *sidp, struct cryptoini *cri)
320{
321 struct padlock_softc *sc = padlock_sc;
322 struct padlock_session *ses = NULL;
323 struct cryptoini *encini, *macini;
324 union padlock_cw *cw;
325
326 if (sc == NULL || sidp == NULL || cri == NULL)
327 return (EINVAL);
328
329 encini = macini = NULL;
330 for (; cri != NULL; cri = cri->cri_next) {
331 switch (cri->cri_alg) {
332 case CRYPTO_NULL_HMAC:
--- 19 unchanged lines hidden (view full) ---
352
353 /*
354 * We only support HMAC algorithms to be able to work with
355 * fast_ipsec(4), so if we are asked only for authentication without
356 * encryption, don't pretend we can accellerate it.
357 */
358 if (encini == NULL)
359 return (EINVAL);
360 if (encini->cri_klen != 128 && encini->cri_klen != 192 &&
361 encini->cri_klen != 256) {
362 return (EINVAL);
363 }
364
365 /*
366 * Let's look for a free session structure.
367 */
368 mtx_lock(&sc->sc_sessions_mtx);
369 /*
370 * Free sessions goes first, so if first session is used, we need to
371 * allocate one.
372 */
373 ses = TAILQ_FIRST(&sc->sc_sessions);
374 if (ses == NULL || ses->ses_used)
375 ses = NULL;
376 else {
377 TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
378 ses->ses_used = 1;
379 TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next);
380 }
381 mtx_unlock(&sc->sc_sessions_mtx);
382 if (ses == NULL) {
383 ses = malloc(sizeof(*ses), M_DEVBUF, M_NOWAIT | M_ZERO);
384 if (ses == NULL)
385 return (ENOMEM);
386 ses->ses_used = 1;
387 mtx_lock(&sc->sc_sessions_mtx);
388 ses->ses_id = sc->sc_sid++;
389 TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next);
390 mtx_unlock(&sc->sc_sessions_mtx);
391 }
392
393 cw = &ses->ses_cw;
394 bzero(cw, sizeof(*cw));
395 cw->cw_algorithm_type = PADLOCK_ALGORITHM_TYPE_AES;
396 cw->cw_key_generation = PADLOCK_KEY_GENERATION_SW;
397 cw->cw_intermediate = 0;
398 switch (encini->cri_klen) {
399 case 128:
400 cw->cw_round_count = PADLOCK_ROUND_COUNT_AES128;
401 cw->cw_key_size = PADLOCK_KEY_SIZE_128;
402#ifdef HW_KEY_GENERATION
403 /* This doesn't buy us much, that's why it is commented out. */
404 cw->cw_key_generation = PADLOCK_KEY_GENERATION_HW;
405#endif
406 break;
407 case 192:
408 cw->cw_round_count = PADLOCK_ROUND_COUNT_AES192;
409 cw->cw_key_size = PADLOCK_KEY_SIZE_192;
410 break;
411 case 256:
412 cw->cw_round_count = PADLOCK_ROUND_COUNT_AES256;
413 cw->cw_key_size = PADLOCK_KEY_SIZE_256;
414 break;
415 }
416 if (encini->cri_key != NULL)
417 padlock_setup_enckey(ses, encini->cri_key, encini->cri_klen);
418
419 arc4rand(ses->ses_iv, sizeof(ses->ses_iv), 0);
420
421 if (macini != NULL) {
422 ses->ses_mlen = macini->cri_mlen;
423
424 /* Find software structure which describes HMAC algorithm. */
425 switch (macini->cri_alg) {
426 case CRYPTO_NULL_HMAC:
427 ses->ses_axf = &auth_hash_null;
428 break;
429 case CRYPTO_MD5_HMAC:
430 ses->ses_axf = &auth_hash_hmac_md5;
431 break;
432 case CRYPTO_SHA1_HMAC:
433 ses->ses_axf = &auth_hash_hmac_sha1;
434 break;
435 case CRYPTO_RIPEMD160_HMAC:
436 ses->ses_axf = &auth_hash_hmac_ripemd_160;
437 break;
438 case CRYPTO_SHA2_256_HMAC:
439 ses->ses_axf = &auth_hash_hmac_sha2_256;
440 break;
441 case CRYPTO_SHA2_384_HMAC:
442 ses->ses_axf = &auth_hash_hmac_sha2_384;
443 break;
444 case CRYPTO_SHA2_512_HMAC:
445 ses->ses_axf = &auth_hash_hmac_sha2_512;
446 break;
447 }
448
449 /* Allocate memory for HMAC inner and outer contexts. */
450 ses->ses_ictx = malloc(ses->ses_axf->ctxsize, M_CRYPTO_DATA,
451 M_NOWAIT);
452 ses->ses_octx = malloc(ses->ses_axf->ctxsize, M_CRYPTO_DATA,
453 M_NOWAIT);
454 if (ses->ses_ictx == NULL || ses->ses_octx == NULL) {
455 padlock_freesession(NULL, ses->ses_id);
456 return (ENOMEM);
457 }
458
459 /* Setup key if given. */
460 if (macini->cri_key != NULL) {
461 padlock_setup_mackey(ses, macini->cri_key,
462 macini->cri_klen);
463 }
464 }
465
466 *sidp = ses->ses_id;
467 return (0);
468}
469
470static int
471padlock_freesession(void *arg __unused, uint64_t tid)
--- 9 unchanged lines hidden (view full) ---
481 if (ses->ses_id == sid)
482 break;
483 }
484 if (ses == NULL) {
485 mtx_unlock(&sc->sc_sessions_mtx);
486 return (EINVAL);
487 }
488 TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
489 if (ses->ses_ictx != NULL) {
490 bzero(ses->ses_ictx, ses->ses_axf->ctxsize);
491 free(ses->ses_ictx, M_CRYPTO_DATA);
492 ses->ses_ictx = NULL;
493 }
494 if (ses->ses_octx != NULL) {
495 bzero(ses->ses_ictx, ses->ses_axf->ctxsize);
496 free(ses->ses_octx, M_CRYPTO_DATA);
497 ses->ses_octx = NULL;
498 }
499 bzero(ses, sizeof(*ses));
500 ses->ses_used = 0;
501 TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next);
502 mtx_unlock(&sc->sc_sessions_mtx);
503 return (0);
504}
505
506static int
507padlock_process(void *arg __unused, struct cryptop *crp, int hint __unused)
508{
509 struct padlock_softc *sc = padlock_sc;
510 struct padlock_session *ses;
511 union padlock_cw *cw;
512 struct cryptodesc *crd, *enccrd, *maccrd;
513 uint32_t *key;
514 u_char *buf, *abuf;
515 int error = 0;
516
517 enccrd = maccrd = NULL;
518 buf = NULL;
519
520 if (crp == NULL || crp->crp_callback == NULL || crp->crp_desc == NULL) {
521 error = EINVAL;
522 goto out;
523 }
524
525 for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) {
526 switch (crd->crd_alg) {
--- 32 unchanged lines hidden (view full) ---
559 break;
560 }
561 mtx_unlock(&sc->sc_sessions_mtx);
562 if (ses == NULL) {
563 error = EINVAL;
564 goto out;
565 }
566
567 buf = malloc(enccrd->crd_len + 16, M_DEVBUF, M_NOWAIT);
568 if (buf == NULL) {
569 error = ENOMEM;
570 goto out;
571 }
572 /* Buffer has to be 16 bytes aligned. */
573 abuf = buf + 16 - ((uintptr_t)buf % 16);
574
575 if ((enccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0)
576 padlock_setup_enckey(ses, enccrd->crd_key, enccrd->crd_klen);
577 if (maccrd != NULL && (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0)
578 padlock_setup_mackey(ses, maccrd->crd_key, maccrd->crd_klen);
579
580 cw = &ses->ses_cw;
581 cw->cw_filler0 = 0;
582 cw->cw_filler1 = 0;
583 cw->cw_filler2 = 0;
584 cw->cw_filler3 = 0;
585 if ((enccrd->crd_flags & CRD_F_ENCRYPT) != 0) {
586 cw->cw_direction = PADLOCK_DIRECTION_ENCRYPT;
587 key = ses->ses_ekey;
588 if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0)
589 bcopy(enccrd->crd_iv, ses->ses_iv, 16);
590
591 if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) {
592 crypto_copyback(crp->crp_flags, crp->crp_buf,
593 enccrd->crd_inject, AES_BLOCK_LEN, ses->ses_iv);
594 }
595 } else {
596 cw->cw_direction = PADLOCK_DIRECTION_DECRYPT;
597 key = ses->ses_dkey;
598 if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0)
599 bcopy(enccrd->crd_iv, ses->ses_iv, AES_BLOCK_LEN);
600 else {
601 crypto_copydata(crp->crp_flags, crp->crp_buf,
602 enccrd->crd_inject, AES_BLOCK_LEN, ses->ses_iv);
603 }
604 }
605
606 /* Perform data authentication if requested before encryption. */
607 if (maccrd != NULL && maccrd->crd_next == enccrd) {
608 error = padlock_authcompute(ses, maccrd, crp->crp_buf,
609 crp->crp_flags);
610 if (error != 0)
611 goto out;
612 }
613
614 crypto_copydata(crp->crp_flags, crp->crp_buf, enccrd->crd_skip,
615 enccrd->crd_len, abuf);
616
617 padlock_cbc(abuf, abuf, enccrd->crd_len / 16, key, cw, ses->ses_iv);
618
619 crypto_copyback(crp->crp_flags, crp->crp_buf, enccrd->crd_skip,
620 enccrd->crd_len, abuf);
621
622 /* Perform data authentication if requested after encryption. */
623 if (maccrd != NULL && enccrd->crd_next == maccrd) {
624 error = padlock_authcompute(ses, maccrd, crp->crp_buf,
625 crp->crp_flags);
626 if (error != 0)
627 goto out;
628 }
629
630 /* copy out last block for use as next session IV */
631 if ((enccrd->crd_flags & CRD_F_ENCRYPT) != 0) {
632 crypto_copydata(crp->crp_flags, crp->crp_buf,
633 enccrd->crd_skip + enccrd->crd_len - AES_BLOCK_LEN,
634 AES_BLOCK_LEN, ses->ses_iv);
635 }
636
637out:
638 if (buf != NULL) {
639 bzero(buf, enccrd->crd_len + 16);
640 free(buf, M_DEVBUF);
641 }
642 crp->crp_etype = error;
643 crypto_done(crp);
644 return (error);
645}
646
647static int
648padlock_modevent(module_t mod, int type, void *unused __unused)
649{
--- 22 unchanged lines hidden ---
2 * Copyright (c) 2005 Pawel Jakub Dawidek
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
--- 8 unchanged lines hidden (view full) ---
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: head/sys/crypto/via/padlock.c 160573 2006-07-22 13:14:11Z 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#if defined(__i386__) && !defined(PC98)
59#include <machine/cpufunc.h>
60#include <machine/cputypes.h>
61#include <machine/md_var.h>
62#include <machine/specialreg.h>
63#endif
64
65#include <opencrypto/cryptodev.h>
66#include <opencrypto/cryptosoft.h> /* for hmac_ipad_buffer and hmac_opad_buffer */
67#include <opencrypto/xform.h>
68#include <crypto/rijndael/rijndael.h>
69
70
71#define PADLOCK_ROUND_COUNT_AES128 10
72#define PADLOCK_ROUND_COUNT_AES192 12
73#define PADLOCK_ROUND_COUNT_AES256 14
74
75#define PADLOCK_ALGORITHM_TYPE_AES 0
76
77#define PADLOCK_KEY_GENERATION_HW 0
78#define PADLOCK_KEY_GENERATION_SW 1
79
80#define PADLOCK_DIRECTION_ENCRYPT 0
81#define PADLOCK_DIRECTION_DECRYPT 1
82
83#define PADLOCK_KEY_SIZE_128 0
84#define PADLOCK_KEY_SIZE_192 1
85#define PADLOCK_KEY_SIZE_256 2
86
87union padlock_cw {
88 uint64_t raw;
89 struct {
90 u_int round_count : 4;
91 u_int algorithm_type : 3;
92 u_int key_generation : 1;
93 u_int intermediate : 1;
94 u_int direction : 1;
95 u_int key_size : 2;
96 u_int filler0 : 20;
97 u_int filler1 : 32;
98 u_int filler2 : 32;
99 u_int filler3 : 32;
100 } __field;
101};
102#define cw_round_count __field.round_count
103#define cw_algorithm_type __field.algorithm_type
104#define cw_key_generation __field.key_generation
105#define cw_intermediate __field.intermediate
106#define cw_direction __field.direction
107#define cw_key_size __field.key_size
108#define cw_filler0 __field.filler0
109#define cw_filler1 __field.filler1
110#define cw_filler2 __field.filler2
111#define cw_filler3 __field.filler3
112
113struct padlock_session {
114 union padlock_cw ses_cw __aligned(16);
115 uint32_t ses_ekey[4 * (RIJNDAEL_MAXNR + 1) + 4] __aligned(16); /* 128 bit aligned */
116 uint32_t ses_dkey[4 * (RIJNDAEL_MAXNR + 1) + 4] __aligned(16); /* 128 bit aligned */
117 uint8_t ses_iv[16] __aligned(16); /* 128 bit aligned */
118 struct auth_hash *ses_axf;
119 uint8_t *ses_ictx;
120 uint8_t *ses_octx;
121 int ses_mlen;
122 int ses_used;
123 uint32_t ses_id;
124 TAILQ_ENTRY(padlock_session) ses_next;
125};
126
127struct padlock_softc {
128 int32_t sc_cid;
129 uint32_t sc_sid;
130 TAILQ_HEAD(, padlock_session) sc_sessions;
131 struct mtx sc_sessions_mtx;
132};
133
134static struct padlock_softc *padlock_sc;
135
136static int padlock_newsession(void *arg __unused, uint32_t *sidp,
137 struct cryptoini *cri);
138static int padlock_freesession(void *arg __unused, uint64_t tid);
139static int padlock_process(void *arg __unused, struct cryptop *crp,
140 int hint __unused);
141
142static __inline void
143padlock_cbc(void *in, void *out, size_t count, void *key, union padlock_cw *cw,
144 void *iv)
145{
146#ifdef __GNUCLIKE_ASM
147 /* The .byte line is really VIA C3 "xcrypt-cbc" instruction */
148 __asm __volatile(
149 "pushf \n\t"
150 "popf \n\t"
151 "rep \n\t"
152 ".byte 0x0f, 0xa7, 0xd0"
153 : "+a" (iv), "+c" (count), "+D" (out), "+S" (in)
154 : "b" (key), "d" (cw)
155 : "cc", "memory"
156 );
157#endif
158}
159
160static int
161padlock_init(void)
162{
163 struct padlock_softc *sc;
164#if defined(__i386__) && !defined(PC98)
165 if (!(via_feature_xcrypt & VIA_HAS_AES)) {
166 printf("PADLOCK: No ACE support.\n");
167 return (EINVAL);
168 } else
169 printf("PADLOCK: HW support loaded.\n");
170#else
171 return (EINVAL);
172#endif
173
174 padlock_sc = sc = malloc(sizeof(*padlock_sc), M_DEVBUF,
175 M_WAITOK | M_ZERO);
176 TAILQ_INIT(&sc->sc_sessions);
177 sc->sc_sid = 1;
178
179 sc->sc_cid = crypto_get_driverid(0);
180 if (sc->sc_cid < 0) {
181 printf("PADLOCK: Could not get crypto driver id.\n");
182 free(padlock_sc, M_DEVBUF);
183 padlock_sc = NULL;
184 return (ENOMEM);
185 }
186
187 mtx_init(&sc->sc_sessions_mtx, "padlock_mtx", NULL, MTX_DEF);
188 crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0, padlock_newsession,
189 padlock_freesession, padlock_process, NULL);
190 crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0, padlock_newsession,
--- 22 unchanged lines hidden (view full) ---
213 return (0);
214 mtx_lock(&sc->sc_sessions_mtx);
215 TAILQ_FOREACH(ses, &sc->sc_sessions, ses_next) {
216 if (ses->ses_used)
217 active++;
218 }
219 if (active > 0) {
220 mtx_unlock(&sc->sc_sessions_mtx);
221 printf("PADLOCK: Cannot destroy, %u sessions active.\n",
222 active);
223 return (EBUSY);
224 }
225 padlock_sc = NULL;
226 for (ses = TAILQ_FIRST(&sc->sc_sessions); ses != NULL;
227 ses = TAILQ_FIRST(&sc->sc_sessions)) {
228 TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
229 free(ses, M_DEVBUF);
230 }
231 mtx_destroy(&sc->sc_sessions_mtx);
232 crypto_unregister_all(sc->sc_cid);
233 free(sc, M_DEVBUF);
234 return (0);
235}
236
237static void
238padlock_setup_enckey(struct padlock_session *ses, caddr_t key, int klen)
239{
240 union padlock_cw *cw;
241 int i;
242
243 cw = &ses->ses_cw;
244 if (cw->cw_key_generation == PADLOCK_KEY_GENERATION_SW) {
245 /* Build expanded keys for both directions */
246 rijndaelKeySetupEnc(ses->ses_ekey, key, klen);
247 rijndaelKeySetupDec(ses->ses_dkey, key, klen);
248 for (i = 0; i < 4 * (RIJNDAEL_MAXNR + 1); i++) {
249 ses->ses_ekey[i] = ntohl(ses->ses_ekey[i]);
250 ses->ses_dkey[i] = ntohl(ses->ses_dkey[i]);
251 }
252 } else {
253 bcopy(key, ses->ses_ekey, klen);
254 bcopy(key, ses->ses_dkey, klen);
255 }
256}
257
258static void
259padlock_setup_mackey(struct padlock_session *ses, caddr_t key, int klen)
260{
261 struct auth_hash *axf;
262 int i;
263
264 klen /= 8;
265 axf = ses->ses_axf;
266
267 for (i = 0; i < klen; i++)
268 key[i] ^= HMAC_IPAD_VAL;
269
270 axf->Init(ses->ses_ictx);
271 axf->Update(ses->ses_ictx, key, klen);
272 axf->Update(ses->ses_ictx, hmac_ipad_buffer, axf->blocksize - klen);
273
274 for (i = 0; i < klen; i++)
275 key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
276
277 axf->Init(ses->ses_octx);
278 axf->Update(ses->ses_octx, key, klen);
279 axf->Update(ses->ses_octx, hmac_opad_buffer, axf->blocksize - klen);
280
281 for (i = 0; i < klen; i++)
282 key[i] ^= HMAC_OPAD_VAL;
283}
284
285/*
286 * Compute keyed-hash authenticator.
287 */
288static int
289padlock_authcompute(struct padlock_session *ses, struct cryptodesc *crd,
290 caddr_t buf, int flags)
291{
292 u_char hash[HASH_MAX_LEN];
293 struct auth_hash *axf;
294 union authctx ctx;
295 int error;
296
297 axf = ses->ses_axf;
298
299 bcopy(ses->ses_ictx, &ctx, axf->ctxsize);
300
301 error = crypto_apply(flags, buf, crd->crd_skip, crd->crd_len,
302 (int (*)(void *, void *, unsigned int))axf->Update, (caddr_t)&ctx);
303 if (error != 0)
304 return (error);
305
306 axf->Final(hash, &ctx);
307 bcopy(ses->ses_octx, &ctx, axf->ctxsize);
308 axf->Update(&ctx, hash, axf->hashsize);
309 axf->Final(hash, &ctx);
310
311 /* Inject the authentication data */
312 crypto_copyback(flags, buf, crd->crd_inject,
313 ses->ses_mlen == 0 ? axf->hashsize : ses->ses_mlen, hash);
314 return (0);
315}
316
317
318static int
319padlock_newsession(void *arg __unused, uint32_t *sidp, struct cryptoini *cri)
320{
321 struct padlock_softc *sc = padlock_sc;
322 struct padlock_session *ses = NULL;
323 struct cryptoini *encini, *macini;
324 union padlock_cw *cw;
325
326 if (sc == NULL || sidp == NULL || cri == NULL)
327 return (EINVAL);
328
329 encini = macini = NULL;
330 for (; cri != NULL; cri = cri->cri_next) {
331 switch (cri->cri_alg) {
332 case CRYPTO_NULL_HMAC:
--- 19 unchanged lines hidden (view full) ---
352
353 /*
354 * We only support HMAC algorithms to be able to work with
355 * fast_ipsec(4), so if we are asked only for authentication without
356 * encryption, don't pretend we can accellerate it.
357 */
358 if (encini == NULL)
359 return (EINVAL);
360 if (encini->cri_klen != 128 && encini->cri_klen != 192 &&
361 encini->cri_klen != 256) {
362 return (EINVAL);
363 }
364
365 /*
366 * Let's look for a free session structure.
367 */
368 mtx_lock(&sc->sc_sessions_mtx);
369 /*
370 * Free sessions goes first, so if first session is used, we need to
371 * allocate one.
372 */
373 ses = TAILQ_FIRST(&sc->sc_sessions);
374 if (ses == NULL || ses->ses_used)
375 ses = NULL;
376 else {
377 TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
378 ses->ses_used = 1;
379 TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next);
380 }
381 mtx_unlock(&sc->sc_sessions_mtx);
382 if (ses == NULL) {
383 ses = malloc(sizeof(*ses), M_DEVBUF, M_NOWAIT | M_ZERO);
384 if (ses == NULL)
385 return (ENOMEM);
386 ses->ses_used = 1;
387 mtx_lock(&sc->sc_sessions_mtx);
388 ses->ses_id = sc->sc_sid++;
389 TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next);
390 mtx_unlock(&sc->sc_sessions_mtx);
391 }
392
393 cw = &ses->ses_cw;
394 bzero(cw, sizeof(*cw));
395 cw->cw_algorithm_type = PADLOCK_ALGORITHM_TYPE_AES;
396 cw->cw_key_generation = PADLOCK_KEY_GENERATION_SW;
397 cw->cw_intermediate = 0;
398 switch (encini->cri_klen) {
399 case 128:
400 cw->cw_round_count = PADLOCK_ROUND_COUNT_AES128;
401 cw->cw_key_size = PADLOCK_KEY_SIZE_128;
402#ifdef HW_KEY_GENERATION
403 /* This doesn't buy us much, that's why it is commented out. */
404 cw->cw_key_generation = PADLOCK_KEY_GENERATION_HW;
405#endif
406 break;
407 case 192:
408 cw->cw_round_count = PADLOCK_ROUND_COUNT_AES192;
409 cw->cw_key_size = PADLOCK_KEY_SIZE_192;
410 break;
411 case 256:
412 cw->cw_round_count = PADLOCK_ROUND_COUNT_AES256;
413 cw->cw_key_size = PADLOCK_KEY_SIZE_256;
414 break;
415 }
416 if (encini->cri_key != NULL)
417 padlock_setup_enckey(ses, encini->cri_key, encini->cri_klen);
418
419 arc4rand(ses->ses_iv, sizeof(ses->ses_iv), 0);
420
421 if (macini != NULL) {
422 ses->ses_mlen = macini->cri_mlen;
423
424 /* Find software structure which describes HMAC algorithm. */
425 switch (macini->cri_alg) {
426 case CRYPTO_NULL_HMAC:
427 ses->ses_axf = &auth_hash_null;
428 break;
429 case CRYPTO_MD5_HMAC:
430 ses->ses_axf = &auth_hash_hmac_md5;
431 break;
432 case CRYPTO_SHA1_HMAC:
433 ses->ses_axf = &auth_hash_hmac_sha1;
434 break;
435 case CRYPTO_RIPEMD160_HMAC:
436 ses->ses_axf = &auth_hash_hmac_ripemd_160;
437 break;
438 case CRYPTO_SHA2_256_HMAC:
439 ses->ses_axf = &auth_hash_hmac_sha2_256;
440 break;
441 case CRYPTO_SHA2_384_HMAC:
442 ses->ses_axf = &auth_hash_hmac_sha2_384;
443 break;
444 case CRYPTO_SHA2_512_HMAC:
445 ses->ses_axf = &auth_hash_hmac_sha2_512;
446 break;
447 }
448
449 /* Allocate memory for HMAC inner and outer contexts. */
450 ses->ses_ictx = malloc(ses->ses_axf->ctxsize, M_CRYPTO_DATA,
451 M_NOWAIT);
452 ses->ses_octx = malloc(ses->ses_axf->ctxsize, M_CRYPTO_DATA,
453 M_NOWAIT);
454 if (ses->ses_ictx == NULL || ses->ses_octx == NULL) {
455 padlock_freesession(NULL, ses->ses_id);
456 return (ENOMEM);
457 }
458
459 /* Setup key if given. */
460 if (macini->cri_key != NULL) {
461 padlock_setup_mackey(ses, macini->cri_key,
462 macini->cri_klen);
463 }
464 }
465
466 *sidp = ses->ses_id;
467 return (0);
468}
469
470static int
471padlock_freesession(void *arg __unused, uint64_t tid)
--- 9 unchanged lines hidden (view full) ---
481 if (ses->ses_id == sid)
482 break;
483 }
484 if (ses == NULL) {
485 mtx_unlock(&sc->sc_sessions_mtx);
486 return (EINVAL);
487 }
488 TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
489 if (ses->ses_ictx != NULL) {
490 bzero(ses->ses_ictx, ses->ses_axf->ctxsize);
491 free(ses->ses_ictx, M_CRYPTO_DATA);
492 ses->ses_ictx = NULL;
493 }
494 if (ses->ses_octx != NULL) {
495 bzero(ses->ses_ictx, ses->ses_axf->ctxsize);
496 free(ses->ses_octx, M_CRYPTO_DATA);
497 ses->ses_octx = NULL;
498 }
499 bzero(ses, sizeof(*ses));
500 ses->ses_used = 0;
501 TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next);
502 mtx_unlock(&sc->sc_sessions_mtx);
503 return (0);
504}
505
506static int
507padlock_process(void *arg __unused, struct cryptop *crp, int hint __unused)
508{
509 struct padlock_softc *sc = padlock_sc;
510 struct padlock_session *ses;
511 union padlock_cw *cw;
512 struct cryptodesc *crd, *enccrd, *maccrd;
513 uint32_t *key;
514 u_char *buf, *abuf;
515 int error = 0;
516
517 enccrd = maccrd = NULL;
518 buf = NULL;
519
520 if (crp == NULL || crp->crp_callback == NULL || crp->crp_desc == NULL) {
521 error = EINVAL;
522 goto out;
523 }
524
525 for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) {
526 switch (crd->crd_alg) {
--- 32 unchanged lines hidden (view full) ---
559 break;
560 }
561 mtx_unlock(&sc->sc_sessions_mtx);
562 if (ses == NULL) {
563 error = EINVAL;
564 goto out;
565 }
566
567 buf = malloc(enccrd->crd_len + 16, M_DEVBUF, M_NOWAIT);
568 if (buf == NULL) {
569 error = ENOMEM;
570 goto out;
571 }
572 /* Buffer has to be 16 bytes aligned. */
573 abuf = buf + 16 - ((uintptr_t)buf % 16);
574
575 if ((enccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0)
576 padlock_setup_enckey(ses, enccrd->crd_key, enccrd->crd_klen);
577 if (maccrd != NULL && (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0)
578 padlock_setup_mackey(ses, maccrd->crd_key, maccrd->crd_klen);
579
580 cw = &ses->ses_cw;
581 cw->cw_filler0 = 0;
582 cw->cw_filler1 = 0;
583 cw->cw_filler2 = 0;
584 cw->cw_filler3 = 0;
585 if ((enccrd->crd_flags & CRD_F_ENCRYPT) != 0) {
586 cw->cw_direction = PADLOCK_DIRECTION_ENCRYPT;
587 key = ses->ses_ekey;
588 if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0)
589 bcopy(enccrd->crd_iv, ses->ses_iv, 16);
590
591 if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) {
592 crypto_copyback(crp->crp_flags, crp->crp_buf,
593 enccrd->crd_inject, AES_BLOCK_LEN, ses->ses_iv);
594 }
595 } else {
596 cw->cw_direction = PADLOCK_DIRECTION_DECRYPT;
597 key = ses->ses_dkey;
598 if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0)
599 bcopy(enccrd->crd_iv, ses->ses_iv, AES_BLOCK_LEN);
600 else {
601 crypto_copydata(crp->crp_flags, crp->crp_buf,
602 enccrd->crd_inject, AES_BLOCK_LEN, ses->ses_iv);
603 }
604 }
605
606 /* Perform data authentication if requested before encryption. */
607 if (maccrd != NULL && maccrd->crd_next == enccrd) {
608 error = padlock_authcompute(ses, maccrd, crp->crp_buf,
609 crp->crp_flags);
610 if (error != 0)
611 goto out;
612 }
613
614 crypto_copydata(crp->crp_flags, crp->crp_buf, enccrd->crd_skip,
615 enccrd->crd_len, abuf);
616
617 padlock_cbc(abuf, abuf, enccrd->crd_len / 16, key, cw, ses->ses_iv);
618
619 crypto_copyback(crp->crp_flags, crp->crp_buf, enccrd->crd_skip,
620 enccrd->crd_len, abuf);
621
622 /* Perform data authentication if requested after encryption. */
623 if (maccrd != NULL && enccrd->crd_next == maccrd) {
624 error = padlock_authcompute(ses, maccrd, crp->crp_buf,
625 crp->crp_flags);
626 if (error != 0)
627 goto out;
628 }
629
630 /* copy out last block for use as next session IV */
631 if ((enccrd->crd_flags & CRD_F_ENCRYPT) != 0) {
632 crypto_copydata(crp->crp_flags, crp->crp_buf,
633 enccrd->crd_skip + enccrd->crd_len - AES_BLOCK_LEN,
634 AES_BLOCK_LEN, ses->ses_iv);
635 }
636
637out:
638 if (buf != NULL) {
639 bzero(buf, enccrd->crd_len + 16);
640 free(buf, M_DEVBUF);
641 }
642 crp->crp_etype = error;
643 crypto_done(crp);
644 return (error);
645}
646
647static int
648padlock_modevent(module_t mod, int type, void *unused __unused)
649{
--- 22 unchanged lines hidden ---