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