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$"); 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); 505