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 #if defined(__i386__) && !defined(PC98) 59ef0a6e20SPawel Jakub Dawidek #include <machine/cpufunc.h> 60ef0a6e20SPawel Jakub Dawidek #include <machine/cputypes.h> 614fd58e10SMichael Reifenberger #include <machine/md_var.h> 624fd58e10SMichael Reifenberger #include <machine/specialreg.h> 63ef0a6e20SPawel Jakub Dawidek #endif 64ef0a6e20SPawel Jakub Dawidek 65ef0a6e20SPawel Jakub Dawidek #include <opencrypto/cryptodev.h> 6664e18040SPawel Jakub Dawidek #include <opencrypto/cryptosoft.h> /* for hmac_ipad_buffer and hmac_opad_buffer */ 6764e18040SPawel Jakub Dawidek #include <opencrypto/xform.h> 68ef0a6e20SPawel Jakub Dawidek #include <crypto/rijndael/rijndael.h> 69ef0a6e20SPawel Jakub Dawidek 70ef0a6e20SPawel Jakub Dawidek 71ef0a6e20SPawel Jakub Dawidek #define PADLOCK_ROUND_COUNT_AES128 10 72ef0a6e20SPawel Jakub Dawidek #define PADLOCK_ROUND_COUNT_AES192 12 73ef0a6e20SPawel Jakub Dawidek #define PADLOCK_ROUND_COUNT_AES256 14 74ef0a6e20SPawel Jakub Dawidek 75ef0a6e20SPawel Jakub Dawidek #define PADLOCK_ALGORITHM_TYPE_AES 0 76ef0a6e20SPawel Jakub Dawidek 77ef0a6e20SPawel Jakub Dawidek #define PADLOCK_KEY_GENERATION_HW 0 78ef0a6e20SPawel Jakub Dawidek #define PADLOCK_KEY_GENERATION_SW 1 79ef0a6e20SPawel Jakub Dawidek 80ef0a6e20SPawel Jakub Dawidek #define PADLOCK_DIRECTION_ENCRYPT 0 81ef0a6e20SPawel Jakub Dawidek #define PADLOCK_DIRECTION_DECRYPT 1 82ef0a6e20SPawel Jakub Dawidek 83ef0a6e20SPawel Jakub Dawidek #define PADLOCK_KEY_SIZE_128 0 84ef0a6e20SPawel Jakub Dawidek #define PADLOCK_KEY_SIZE_192 1 85ef0a6e20SPawel Jakub Dawidek #define PADLOCK_KEY_SIZE_256 2 86ef0a6e20SPawel Jakub Dawidek 87ef0a6e20SPawel Jakub Dawidek union padlock_cw { 88ef0a6e20SPawel Jakub Dawidek uint64_t raw; 89ef0a6e20SPawel Jakub Dawidek struct { 90ef0a6e20SPawel Jakub Dawidek u_int round_count : 4; 91ef0a6e20SPawel Jakub Dawidek u_int algorithm_type : 3; 92ef0a6e20SPawel Jakub Dawidek u_int key_generation : 1; 93ef0a6e20SPawel Jakub Dawidek u_int intermediate : 1; 94ef0a6e20SPawel Jakub Dawidek u_int direction : 1; 95ef0a6e20SPawel Jakub Dawidek u_int key_size : 2; 96ef0a6e20SPawel Jakub Dawidek u_int filler0 : 20; 97ef0a6e20SPawel Jakub Dawidek u_int filler1 : 32; 98ef0a6e20SPawel Jakub Dawidek u_int filler2 : 32; 99ef0a6e20SPawel Jakub Dawidek u_int filler3 : 32; 100ef0a6e20SPawel Jakub Dawidek } __field; 101ef0a6e20SPawel Jakub Dawidek }; 102ef0a6e20SPawel Jakub Dawidek #define cw_round_count __field.round_count 103ef0a6e20SPawel Jakub Dawidek #define cw_algorithm_type __field.algorithm_type 104ef0a6e20SPawel Jakub Dawidek #define cw_key_generation __field.key_generation 105ef0a6e20SPawel Jakub Dawidek #define cw_intermediate __field.intermediate 106ef0a6e20SPawel Jakub Dawidek #define cw_direction __field.direction 107ef0a6e20SPawel Jakub Dawidek #define cw_key_size __field.key_size 108ef0a6e20SPawel Jakub Dawidek #define cw_filler0 __field.filler0 109ef0a6e20SPawel Jakub Dawidek #define cw_filler1 __field.filler1 110ef0a6e20SPawel Jakub Dawidek #define cw_filler2 __field.filler2 111ef0a6e20SPawel Jakub Dawidek #define cw_filler3 __field.filler3 112ef0a6e20SPawel Jakub Dawidek 113ef0a6e20SPawel Jakub Dawidek struct padlock_session { 114ef0a6e20SPawel Jakub Dawidek union padlock_cw ses_cw __aligned(16); 115ef0a6e20SPawel Jakub Dawidek uint32_t ses_ekey[4 * (RIJNDAEL_MAXNR + 1) + 4] __aligned(16); /* 128 bit aligned */ 116ef0a6e20SPawel Jakub Dawidek uint32_t ses_dkey[4 * (RIJNDAEL_MAXNR + 1) + 4] __aligned(16); /* 128 bit aligned */ 117ef0a6e20SPawel Jakub Dawidek uint8_t ses_iv[16] __aligned(16); /* 128 bit aligned */ 11864e18040SPawel Jakub Dawidek struct auth_hash *ses_axf; 11964e18040SPawel Jakub Dawidek uint8_t *ses_ictx; 12064e18040SPawel Jakub Dawidek uint8_t *ses_octx; 12164e18040SPawel Jakub Dawidek int ses_mlen; 122ef0a6e20SPawel Jakub Dawidek int ses_used; 123ef0a6e20SPawel Jakub Dawidek uint32_t ses_id; 124ef0a6e20SPawel Jakub Dawidek TAILQ_ENTRY(padlock_session) ses_next; 125ef0a6e20SPawel Jakub Dawidek }; 126ef0a6e20SPawel Jakub Dawidek 127ef0a6e20SPawel Jakub Dawidek struct padlock_softc { 128ef0a6e20SPawel Jakub Dawidek int32_t sc_cid; 129ef0a6e20SPawel Jakub Dawidek uint32_t sc_sid; 130ef0a6e20SPawel Jakub Dawidek TAILQ_HEAD(, padlock_session) sc_sessions; 131ef0a6e20SPawel Jakub Dawidek struct mtx sc_sessions_mtx; 132ef0a6e20SPawel Jakub Dawidek }; 133ef0a6e20SPawel Jakub Dawidek 134ef0a6e20SPawel Jakub Dawidek static struct padlock_softc *padlock_sc; 135ef0a6e20SPawel Jakub Dawidek 136ef0a6e20SPawel Jakub Dawidek static int padlock_newsession(void *arg __unused, uint32_t *sidp, 137ef0a6e20SPawel Jakub Dawidek struct cryptoini *cri); 138ef0a6e20SPawel Jakub Dawidek static int padlock_freesession(void *arg __unused, uint64_t tid); 139ef0a6e20SPawel Jakub Dawidek static int padlock_process(void *arg __unused, struct cryptop *crp, 140ef0a6e20SPawel Jakub Dawidek int hint __unused); 141ef0a6e20SPawel Jakub Dawidek 142ef0a6e20SPawel Jakub Dawidek static __inline void 143ef0a6e20SPawel Jakub Dawidek padlock_cbc(void *in, void *out, size_t count, void *key, union padlock_cw *cw, 144ef0a6e20SPawel Jakub Dawidek void *iv) 145ef0a6e20SPawel Jakub Dawidek { 146ef0a6e20SPawel Jakub Dawidek #ifdef __GNUCLIKE_ASM 147ef0a6e20SPawel Jakub Dawidek /* The .byte line is really VIA C3 "xcrypt-cbc" instruction */ 148ef0a6e20SPawel Jakub Dawidek __asm __volatile( 149ef0a6e20SPawel Jakub Dawidek "pushf \n\t" 150ef0a6e20SPawel Jakub Dawidek "popf \n\t" 151ef0a6e20SPawel Jakub Dawidek "rep \n\t" 152ef0a6e20SPawel Jakub Dawidek ".byte 0x0f, 0xa7, 0xd0" 153ef0a6e20SPawel Jakub Dawidek : "+a" (iv), "+c" (count), "+D" (out), "+S" (in) 154ef0a6e20SPawel Jakub Dawidek : "b" (key), "d" (cw) 155ef0a6e20SPawel Jakub Dawidek : "cc", "memory" 156ef0a6e20SPawel Jakub Dawidek ); 157ef0a6e20SPawel Jakub Dawidek #endif 158ef0a6e20SPawel Jakub Dawidek } 159ef0a6e20SPawel Jakub Dawidek 160ef0a6e20SPawel Jakub Dawidek static int 161ef0a6e20SPawel Jakub Dawidek padlock_init(void) 162ef0a6e20SPawel Jakub Dawidek { 163ef0a6e20SPawel Jakub Dawidek struct padlock_softc *sc; 164ef0a6e20SPawel Jakub Dawidek #if defined(__i386__) && !defined(PC98) 1654fd58e10SMichael Reifenberger if (!(via_feature_xcrypt & VIA_HAS_AES)) { 166ef0a6e20SPawel Jakub Dawidek printf("PADLOCK: No ACE support.\n"); 167ef0a6e20SPawel Jakub Dawidek return (EINVAL); 1684fd58e10SMichael Reifenberger } else 1694fd58e10SMichael Reifenberger printf("PADLOCK: HW support loaded.\n"); 170ef0a6e20SPawel Jakub Dawidek #else 171ef0a6e20SPawel Jakub Dawidek return (EINVAL); 172ef0a6e20SPawel Jakub Dawidek #endif 173ef0a6e20SPawel Jakub Dawidek 174ef0a6e20SPawel Jakub Dawidek padlock_sc = sc = malloc(sizeof(*padlock_sc), M_DEVBUF, 175f3b67db3SPawel Jakub Dawidek M_WAITOK | M_ZERO); 176ef0a6e20SPawel Jakub Dawidek TAILQ_INIT(&sc->sc_sessions); 177ef0a6e20SPawel Jakub Dawidek sc->sc_sid = 1; 178ef0a6e20SPawel Jakub Dawidek 179ef0a6e20SPawel Jakub Dawidek sc->sc_cid = crypto_get_driverid(0); 180ef0a6e20SPawel Jakub Dawidek if (sc->sc_cid < 0) { 181ef0a6e20SPawel Jakub Dawidek printf("PADLOCK: Could not get crypto driver id.\n"); 182ef0a6e20SPawel Jakub Dawidek free(padlock_sc, M_DEVBUF); 183ef0a6e20SPawel Jakub Dawidek padlock_sc = NULL; 184ef0a6e20SPawel Jakub Dawidek return (ENOMEM); 185ef0a6e20SPawel Jakub Dawidek } 186ef0a6e20SPawel Jakub Dawidek 187ef0a6e20SPawel Jakub Dawidek mtx_init(&sc->sc_sessions_mtx, "padlock_mtx", NULL, MTX_DEF); 188ef0a6e20SPawel Jakub Dawidek crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0, padlock_newsession, 189ef0a6e20SPawel Jakub Dawidek padlock_freesession, padlock_process, NULL); 19064e18040SPawel Jakub Dawidek crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0, padlock_newsession, 19164e18040SPawel Jakub Dawidek padlock_freesession, padlock_process, NULL); 19264e18040SPawel Jakub Dawidek crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0, padlock_newsession, 19364e18040SPawel Jakub Dawidek padlock_freesession, padlock_process, NULL); 19464e18040SPawel Jakub Dawidek crypto_register(sc->sc_cid, CRYPTO_RIPEMD160_HMAC, 0, 0, 19564e18040SPawel Jakub Dawidek padlock_newsession, padlock_freesession, padlock_process, NULL); 19664e18040SPawel Jakub Dawidek crypto_register(sc->sc_cid, CRYPTO_SHA2_256_HMAC, 0, 0, 19764e18040SPawel Jakub Dawidek padlock_newsession, padlock_freesession, padlock_process, NULL); 19864e18040SPawel Jakub Dawidek crypto_register(sc->sc_cid, CRYPTO_SHA2_384_HMAC, 0, 0, 19964e18040SPawel Jakub Dawidek padlock_newsession, padlock_freesession, padlock_process, NULL); 20064e18040SPawel Jakub Dawidek crypto_register(sc->sc_cid, CRYPTO_SHA2_512_HMAC, 0, 0, 20164e18040SPawel Jakub Dawidek padlock_newsession, padlock_freesession, padlock_process, NULL); 202ef0a6e20SPawel Jakub Dawidek return (0); 203ef0a6e20SPawel Jakub Dawidek } 204ef0a6e20SPawel Jakub Dawidek 205ef0a6e20SPawel Jakub Dawidek static int 206ef0a6e20SPawel Jakub Dawidek padlock_destroy(void) 207ef0a6e20SPawel Jakub Dawidek { 208ef0a6e20SPawel Jakub Dawidek struct padlock_softc *sc = padlock_sc; 209ef0a6e20SPawel Jakub Dawidek struct padlock_session *ses; 210ef0a6e20SPawel Jakub Dawidek u_int active = 0; 211ef0a6e20SPawel Jakub Dawidek 212ef0a6e20SPawel Jakub Dawidek if (sc == NULL) 213ef0a6e20SPawel Jakub Dawidek return (0); 214ef0a6e20SPawel Jakub Dawidek mtx_lock(&sc->sc_sessions_mtx); 215ef0a6e20SPawel Jakub Dawidek TAILQ_FOREACH(ses, &sc->sc_sessions, ses_next) { 216ef0a6e20SPawel Jakub Dawidek if (ses->ses_used) 217ef0a6e20SPawel Jakub Dawidek active++; 218ef0a6e20SPawel Jakub Dawidek } 219ef0a6e20SPawel Jakub Dawidek if (active > 0) { 220ef0a6e20SPawel Jakub Dawidek mtx_unlock(&sc->sc_sessions_mtx); 221ef0a6e20SPawel Jakub Dawidek printf("PADLOCK: Cannot destroy, %u sessions active.\n", 222ef0a6e20SPawel Jakub Dawidek active); 223ef0a6e20SPawel Jakub Dawidek return (EBUSY); 224ef0a6e20SPawel Jakub Dawidek } 225ef0a6e20SPawel Jakub Dawidek padlock_sc = NULL; 226ef0a6e20SPawel Jakub Dawidek for (ses = TAILQ_FIRST(&sc->sc_sessions); ses != NULL; 227ef0a6e20SPawel Jakub Dawidek ses = TAILQ_FIRST(&sc->sc_sessions)) { 228ef0a6e20SPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next); 229ef0a6e20SPawel Jakub Dawidek free(ses, M_DEVBUF); 230ef0a6e20SPawel Jakub Dawidek } 231ef0a6e20SPawel Jakub Dawidek mtx_destroy(&sc->sc_sessions_mtx); 232ef0a6e20SPawel Jakub Dawidek crypto_unregister_all(sc->sc_cid); 233ef0a6e20SPawel Jakub Dawidek free(sc, M_DEVBUF); 234ef0a6e20SPawel Jakub Dawidek return (0); 235ef0a6e20SPawel Jakub Dawidek } 236ef0a6e20SPawel Jakub Dawidek 23764e18040SPawel Jakub Dawidek static void 23864e18040SPawel Jakub Dawidek padlock_setup_enckey(struct padlock_session *ses, caddr_t key, int klen) 23964e18040SPawel Jakub Dawidek { 24064e18040SPawel Jakub Dawidek union padlock_cw *cw; 24164e18040SPawel Jakub Dawidek int i; 24264e18040SPawel Jakub Dawidek 24364e18040SPawel Jakub Dawidek cw = &ses->ses_cw; 24464e18040SPawel Jakub Dawidek if (cw->cw_key_generation == PADLOCK_KEY_GENERATION_SW) { 24564e18040SPawel Jakub Dawidek /* Build expanded keys for both directions */ 24664e18040SPawel Jakub Dawidek rijndaelKeySetupEnc(ses->ses_ekey, key, klen); 24764e18040SPawel Jakub Dawidek rijndaelKeySetupDec(ses->ses_dkey, key, klen); 24864e18040SPawel Jakub Dawidek for (i = 0; i < 4 * (RIJNDAEL_MAXNR + 1); i++) { 24964e18040SPawel Jakub Dawidek ses->ses_ekey[i] = ntohl(ses->ses_ekey[i]); 25064e18040SPawel Jakub Dawidek ses->ses_dkey[i] = ntohl(ses->ses_dkey[i]); 25164e18040SPawel Jakub Dawidek } 25264e18040SPawel Jakub Dawidek } else { 25364e18040SPawel Jakub Dawidek bcopy(key, ses->ses_ekey, klen); 25464e18040SPawel Jakub Dawidek bcopy(key, ses->ses_dkey, klen); 25564e18040SPawel Jakub Dawidek } 25664e18040SPawel Jakub Dawidek } 25764e18040SPawel Jakub Dawidek 25864e18040SPawel Jakub Dawidek static void 25964e18040SPawel Jakub Dawidek padlock_setup_mackey(struct padlock_session *ses, caddr_t key, int klen) 26064e18040SPawel Jakub Dawidek { 26164e18040SPawel Jakub Dawidek struct auth_hash *axf; 26264e18040SPawel Jakub Dawidek int i; 26364e18040SPawel Jakub Dawidek 26464e18040SPawel Jakub Dawidek klen /= 8; 26564e18040SPawel Jakub Dawidek axf = ses->ses_axf; 26664e18040SPawel Jakub Dawidek 26764e18040SPawel Jakub Dawidek for (i = 0; i < klen; i++) 26864e18040SPawel Jakub Dawidek key[i] ^= HMAC_IPAD_VAL; 26964e18040SPawel Jakub Dawidek 27064e18040SPawel Jakub Dawidek axf->Init(ses->ses_ictx); 27164e18040SPawel Jakub Dawidek axf->Update(ses->ses_ictx, key, klen); 27264e18040SPawel Jakub Dawidek axf->Update(ses->ses_ictx, hmac_ipad_buffer, axf->blocksize - klen); 27364e18040SPawel Jakub Dawidek 27464e18040SPawel Jakub Dawidek for (i = 0; i < klen; i++) 27564e18040SPawel Jakub Dawidek key[i] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL); 27664e18040SPawel Jakub Dawidek 27764e18040SPawel Jakub Dawidek axf->Init(ses->ses_octx); 27864e18040SPawel Jakub Dawidek axf->Update(ses->ses_octx, key, klen); 27964e18040SPawel Jakub Dawidek axf->Update(ses->ses_octx, hmac_opad_buffer, axf->blocksize - klen); 28064e18040SPawel Jakub Dawidek 28164e18040SPawel Jakub Dawidek for (i = 0; i < klen; i++) 28264e18040SPawel Jakub Dawidek key[i] ^= HMAC_OPAD_VAL; 28364e18040SPawel Jakub Dawidek } 28464e18040SPawel Jakub Dawidek 28564e18040SPawel Jakub Dawidek /* 28664e18040SPawel Jakub Dawidek * Compute keyed-hash authenticator. 28764e18040SPawel Jakub Dawidek */ 28864e18040SPawel Jakub Dawidek static int 28964e18040SPawel Jakub Dawidek padlock_authcompute(struct padlock_session *ses, struct cryptodesc *crd, 29064e18040SPawel Jakub Dawidek caddr_t buf, int flags) 29164e18040SPawel Jakub Dawidek { 29264e18040SPawel Jakub Dawidek u_char hash[HASH_MAX_LEN]; 29364e18040SPawel Jakub Dawidek struct auth_hash *axf; 29464e18040SPawel Jakub Dawidek union authctx ctx; 29564e18040SPawel Jakub Dawidek int error; 29664e18040SPawel Jakub Dawidek 29764e18040SPawel Jakub Dawidek axf = ses->ses_axf; 29864e18040SPawel Jakub Dawidek 29964e18040SPawel Jakub Dawidek bcopy(ses->ses_ictx, &ctx, axf->ctxsize); 30064e18040SPawel Jakub Dawidek 30164e18040SPawel Jakub Dawidek error = crypto_apply(flags, buf, crd->crd_skip, crd->crd_len, 30264e18040SPawel Jakub Dawidek (int (*)(void *, void *, unsigned int))axf->Update, (caddr_t)&ctx); 30364e18040SPawel Jakub Dawidek if (error != 0) 30464e18040SPawel Jakub Dawidek return (error); 30564e18040SPawel Jakub Dawidek 30664e18040SPawel Jakub Dawidek axf->Final(hash, &ctx); 30764e18040SPawel Jakub Dawidek bcopy(ses->ses_octx, &ctx, axf->ctxsize); 30864e18040SPawel Jakub Dawidek axf->Update(&ctx, hash, axf->hashsize); 30964e18040SPawel Jakub Dawidek axf->Final(hash, &ctx); 31064e18040SPawel Jakub Dawidek 31164e18040SPawel Jakub Dawidek /* Inject the authentication data */ 31264e18040SPawel Jakub Dawidek crypto_copyback(flags, buf, crd->crd_inject, 31364e18040SPawel Jakub Dawidek ses->ses_mlen == 0 ? axf->hashsize : ses->ses_mlen, hash); 31464e18040SPawel Jakub Dawidek return (0); 31564e18040SPawel Jakub Dawidek } 31664e18040SPawel Jakub Dawidek 31764e18040SPawel Jakub Dawidek 318ef0a6e20SPawel Jakub Dawidek static int 319ef0a6e20SPawel Jakub Dawidek padlock_newsession(void *arg __unused, uint32_t *sidp, struct cryptoini *cri) 320ef0a6e20SPawel Jakub Dawidek { 321ef0a6e20SPawel Jakub Dawidek struct padlock_softc *sc = padlock_sc; 322ef0a6e20SPawel Jakub Dawidek struct padlock_session *ses = NULL; 32364e18040SPawel Jakub Dawidek struct cryptoini *encini, *macini; 324ef0a6e20SPawel Jakub Dawidek union padlock_cw *cw; 325ef0a6e20SPawel Jakub Dawidek 32664e18040SPawel Jakub Dawidek if (sc == NULL || sidp == NULL || cri == NULL) 32764e18040SPawel Jakub Dawidek return (EINVAL); 32864e18040SPawel Jakub Dawidek 32964e18040SPawel Jakub Dawidek encini = macini = NULL; 33064e18040SPawel Jakub Dawidek for (; cri != NULL; cri = cri->cri_next) { 33164e18040SPawel Jakub Dawidek switch (cri->cri_alg) { 33264e18040SPawel Jakub Dawidek case CRYPTO_NULL_HMAC: 33364e18040SPawel Jakub Dawidek case CRYPTO_MD5_HMAC: 33464e18040SPawel Jakub Dawidek case CRYPTO_SHA1_HMAC: 33564e18040SPawel Jakub Dawidek case CRYPTO_RIPEMD160_HMAC: 33664e18040SPawel Jakub Dawidek case CRYPTO_SHA2_256_HMAC: 33764e18040SPawel Jakub Dawidek case CRYPTO_SHA2_384_HMAC: 33864e18040SPawel Jakub Dawidek case CRYPTO_SHA2_512_HMAC: 33964e18040SPawel Jakub Dawidek if (macini != NULL) 34064e18040SPawel Jakub Dawidek return (EINVAL); 34164e18040SPawel Jakub Dawidek macini = cri; 34264e18040SPawel Jakub Dawidek break; 34364e18040SPawel Jakub Dawidek case CRYPTO_AES_CBC: 34464e18040SPawel Jakub Dawidek if (encini != NULL) 34564e18040SPawel Jakub Dawidek return (EINVAL); 34664e18040SPawel Jakub Dawidek encini = cri; 34764e18040SPawel Jakub Dawidek break; 34864e18040SPawel Jakub Dawidek default: 349ef0a6e20SPawel Jakub Dawidek return (EINVAL); 350ef0a6e20SPawel Jakub Dawidek } 35164e18040SPawel Jakub Dawidek } 35264e18040SPawel Jakub Dawidek 35364e18040SPawel Jakub Dawidek /* 35464e18040SPawel Jakub Dawidek * We only support HMAC algorithms to be able to work with 35564e18040SPawel Jakub Dawidek * fast_ipsec(4), so if we are asked only for authentication without 35664e18040SPawel Jakub Dawidek * encryption, don't pretend we can accellerate it. 35764e18040SPawel Jakub Dawidek */ 35864e18040SPawel Jakub Dawidek if (encini == NULL) 35964e18040SPawel Jakub Dawidek return (EINVAL); 36064e18040SPawel Jakub Dawidek if (encini->cri_klen != 128 && encini->cri_klen != 192 && 36164e18040SPawel Jakub Dawidek encini->cri_klen != 256) { 362ef0a6e20SPawel Jakub Dawidek return (EINVAL); 363ef0a6e20SPawel Jakub Dawidek } 364ef0a6e20SPawel Jakub Dawidek 365ef0a6e20SPawel Jakub Dawidek /* 366ef0a6e20SPawel Jakub Dawidek * Let's look for a free session structure. 367ef0a6e20SPawel Jakub Dawidek */ 368ef0a6e20SPawel Jakub Dawidek mtx_lock(&sc->sc_sessions_mtx); 369ef0a6e20SPawel Jakub Dawidek /* 370ef0a6e20SPawel Jakub Dawidek * Free sessions goes first, so if first session is used, we need to 371ef0a6e20SPawel Jakub Dawidek * allocate one. 372ef0a6e20SPawel Jakub Dawidek */ 373ef0a6e20SPawel Jakub Dawidek ses = TAILQ_FIRST(&sc->sc_sessions); 374ef0a6e20SPawel Jakub Dawidek if (ses == NULL || ses->ses_used) 375ef0a6e20SPawel Jakub Dawidek ses = NULL; 376ef0a6e20SPawel Jakub Dawidek else { 377ef0a6e20SPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next); 378ef0a6e20SPawel Jakub Dawidek ses->ses_used = 1; 379ef0a6e20SPawel Jakub Dawidek TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next); 380ef0a6e20SPawel Jakub Dawidek } 381ef0a6e20SPawel Jakub Dawidek mtx_unlock(&sc->sc_sessions_mtx); 382ef0a6e20SPawel Jakub Dawidek if (ses == NULL) { 383ef0a6e20SPawel Jakub Dawidek ses = malloc(sizeof(*ses), M_DEVBUF, M_NOWAIT | M_ZERO); 384ef0a6e20SPawel Jakub Dawidek if (ses == NULL) 385ef0a6e20SPawel Jakub Dawidek return (ENOMEM); 386ef0a6e20SPawel Jakub Dawidek ses->ses_used = 1; 387ef0a6e20SPawel Jakub Dawidek mtx_lock(&sc->sc_sessions_mtx); 388ef0a6e20SPawel Jakub Dawidek ses->ses_id = sc->sc_sid++; 389ef0a6e20SPawel Jakub Dawidek TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next); 390ef0a6e20SPawel Jakub Dawidek mtx_unlock(&sc->sc_sessions_mtx); 391ef0a6e20SPawel Jakub Dawidek } 392ef0a6e20SPawel Jakub Dawidek 393ef0a6e20SPawel Jakub Dawidek cw = &ses->ses_cw; 394ef0a6e20SPawel Jakub Dawidek bzero(cw, sizeof(*cw)); 395ef0a6e20SPawel Jakub Dawidek cw->cw_algorithm_type = PADLOCK_ALGORITHM_TYPE_AES; 396ef0a6e20SPawel Jakub Dawidek cw->cw_key_generation = PADLOCK_KEY_GENERATION_SW; 397ef0a6e20SPawel Jakub Dawidek cw->cw_intermediate = 0; 39864e18040SPawel Jakub Dawidek switch (encini->cri_klen) { 399ef0a6e20SPawel Jakub Dawidek case 128: 400ef0a6e20SPawel Jakub Dawidek cw->cw_round_count = PADLOCK_ROUND_COUNT_AES128; 401ef0a6e20SPawel Jakub Dawidek cw->cw_key_size = PADLOCK_KEY_SIZE_128; 402ef0a6e20SPawel Jakub Dawidek #ifdef HW_KEY_GENERATION 403ef0a6e20SPawel Jakub Dawidek /* This doesn't buy us much, that's why it is commented out. */ 404ef0a6e20SPawel Jakub Dawidek cw->cw_key_generation = PADLOCK_KEY_GENERATION_HW; 405ef0a6e20SPawel Jakub Dawidek #endif 406ef0a6e20SPawel Jakub Dawidek break; 407ef0a6e20SPawel Jakub Dawidek case 192: 408ef0a6e20SPawel Jakub Dawidek cw->cw_round_count = PADLOCK_ROUND_COUNT_AES192; 409ef0a6e20SPawel Jakub Dawidek cw->cw_key_size = PADLOCK_KEY_SIZE_192; 410ef0a6e20SPawel Jakub Dawidek break; 411ef0a6e20SPawel Jakub Dawidek case 256: 412ef0a6e20SPawel Jakub Dawidek cw->cw_round_count = PADLOCK_ROUND_COUNT_AES256; 413ef0a6e20SPawel Jakub Dawidek cw->cw_key_size = PADLOCK_KEY_SIZE_256; 414ef0a6e20SPawel Jakub Dawidek break; 415ef0a6e20SPawel Jakub Dawidek } 41664e18040SPawel Jakub Dawidek if (encini->cri_key != NULL) 41764e18040SPawel Jakub Dawidek padlock_setup_enckey(ses, encini->cri_key, encini->cri_klen); 418ef0a6e20SPawel Jakub Dawidek 419ef0a6e20SPawel Jakub Dawidek arc4rand(ses->ses_iv, sizeof(ses->ses_iv), 0); 420ef0a6e20SPawel Jakub Dawidek 42164e18040SPawel Jakub Dawidek if (macini != NULL) { 42264e18040SPawel Jakub Dawidek ses->ses_mlen = macini->cri_mlen; 42364e18040SPawel Jakub Dawidek 42464e18040SPawel Jakub Dawidek /* Find software structure which describes HMAC algorithm. */ 42564e18040SPawel Jakub Dawidek switch (macini->cri_alg) { 42664e18040SPawel Jakub Dawidek case CRYPTO_NULL_HMAC: 42764e18040SPawel Jakub Dawidek ses->ses_axf = &auth_hash_null; 42864e18040SPawel Jakub Dawidek break; 42964e18040SPawel Jakub Dawidek case CRYPTO_MD5_HMAC: 43064e18040SPawel Jakub Dawidek ses->ses_axf = &auth_hash_hmac_md5; 43164e18040SPawel Jakub Dawidek break; 43264e18040SPawel Jakub Dawidek case CRYPTO_SHA1_HMAC: 43364e18040SPawel Jakub Dawidek ses->ses_axf = &auth_hash_hmac_sha1; 43464e18040SPawel Jakub Dawidek break; 43564e18040SPawel Jakub Dawidek case CRYPTO_RIPEMD160_HMAC: 43664e18040SPawel Jakub Dawidek ses->ses_axf = &auth_hash_hmac_ripemd_160; 43764e18040SPawel Jakub Dawidek break; 43864e18040SPawel Jakub Dawidek case CRYPTO_SHA2_256_HMAC: 43964e18040SPawel Jakub Dawidek ses->ses_axf = &auth_hash_hmac_sha2_256; 44064e18040SPawel Jakub Dawidek break; 44164e18040SPawel Jakub Dawidek case CRYPTO_SHA2_384_HMAC: 44264e18040SPawel Jakub Dawidek ses->ses_axf = &auth_hash_hmac_sha2_384; 44364e18040SPawel Jakub Dawidek break; 44464e18040SPawel Jakub Dawidek case CRYPTO_SHA2_512_HMAC: 44564e18040SPawel Jakub Dawidek ses->ses_axf = &auth_hash_hmac_sha2_512; 44664e18040SPawel Jakub Dawidek break; 447ef0a6e20SPawel Jakub Dawidek } 44864e18040SPawel Jakub Dawidek 44964e18040SPawel Jakub Dawidek /* Allocate memory for HMAC inner and outer contexts. */ 45064e18040SPawel Jakub Dawidek ses->ses_ictx = malloc(ses->ses_axf->ctxsize, M_CRYPTO_DATA, 45164e18040SPawel Jakub Dawidek M_NOWAIT); 45264e18040SPawel Jakub Dawidek ses->ses_octx = malloc(ses->ses_axf->ctxsize, M_CRYPTO_DATA, 45364e18040SPawel Jakub Dawidek M_NOWAIT); 45464e18040SPawel Jakub Dawidek if (ses->ses_ictx == NULL || ses->ses_octx == NULL) { 45564e18040SPawel Jakub Dawidek padlock_freesession(NULL, ses->ses_id); 45664e18040SPawel Jakub Dawidek return (ENOMEM); 45764e18040SPawel Jakub Dawidek } 45864e18040SPawel Jakub Dawidek 45964e18040SPawel Jakub Dawidek /* Setup key if given. */ 46064e18040SPawel Jakub Dawidek if (macini->cri_key != NULL) { 46164e18040SPawel Jakub Dawidek padlock_setup_mackey(ses, macini->cri_key, 46264e18040SPawel Jakub Dawidek macini->cri_klen); 46364e18040SPawel Jakub Dawidek } 464ef0a6e20SPawel Jakub Dawidek } 465ef0a6e20SPawel Jakub Dawidek 466ef0a6e20SPawel Jakub Dawidek *sidp = ses->ses_id; 467ef0a6e20SPawel Jakub Dawidek return (0); 468ef0a6e20SPawel Jakub Dawidek } 469ef0a6e20SPawel Jakub Dawidek 470ef0a6e20SPawel Jakub Dawidek static int 471ef0a6e20SPawel Jakub Dawidek padlock_freesession(void *arg __unused, uint64_t tid) 472ef0a6e20SPawel Jakub Dawidek { 473ef0a6e20SPawel Jakub Dawidek struct padlock_softc *sc = padlock_sc; 474ef0a6e20SPawel Jakub Dawidek struct padlock_session *ses; 475ef0a6e20SPawel Jakub Dawidek uint32_t sid = ((uint32_t)tid) & 0xffffffff; 476ef0a6e20SPawel Jakub Dawidek 477ef0a6e20SPawel Jakub Dawidek if (sc == NULL) 478ef0a6e20SPawel Jakub Dawidek return (EINVAL); 479ef0a6e20SPawel Jakub Dawidek mtx_lock(&sc->sc_sessions_mtx); 480ef0a6e20SPawel Jakub Dawidek TAILQ_FOREACH(ses, &sc->sc_sessions, ses_next) { 481ef0a6e20SPawel Jakub Dawidek if (ses->ses_id == sid) 482ef0a6e20SPawel Jakub Dawidek break; 483ef0a6e20SPawel Jakub Dawidek } 484ef0a6e20SPawel Jakub Dawidek if (ses == NULL) { 485ef0a6e20SPawel Jakub Dawidek mtx_unlock(&sc->sc_sessions_mtx); 486ef0a6e20SPawel Jakub Dawidek return (EINVAL); 487ef0a6e20SPawel Jakub Dawidek } 488ef0a6e20SPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next); 48964e18040SPawel Jakub Dawidek if (ses->ses_ictx != NULL) { 49064e18040SPawel Jakub Dawidek bzero(ses->ses_ictx, sizeof(ses->ses_ictx)); 49164e18040SPawel Jakub Dawidek free(ses->ses_ictx, M_CRYPTO_DATA); 49264e18040SPawel Jakub Dawidek } 49364e18040SPawel Jakub Dawidek if (ses->ses_octx != NULL) { 49464e18040SPawel Jakub Dawidek bzero(ses->ses_octx, sizeof(ses->ses_octx)); 49564e18040SPawel Jakub Dawidek free(ses->ses_octx, M_CRYPTO_DATA); 49664e18040SPawel Jakub Dawidek } 497ef0a6e20SPawel Jakub Dawidek bzero(ses, sizeof(ses)); 498ef0a6e20SPawel Jakub Dawidek ses->ses_used = 0; 499ef0a6e20SPawel Jakub Dawidek TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next); 500ef0a6e20SPawel Jakub Dawidek mtx_unlock(&sc->sc_sessions_mtx); 501ef0a6e20SPawel Jakub Dawidek return (0); 502ef0a6e20SPawel Jakub Dawidek } 503ef0a6e20SPawel Jakub Dawidek 504ef0a6e20SPawel Jakub Dawidek static int 505ef0a6e20SPawel Jakub Dawidek padlock_process(void *arg __unused, struct cryptop *crp, int hint __unused) 506ef0a6e20SPawel Jakub Dawidek { 507ef0a6e20SPawel Jakub Dawidek struct padlock_softc *sc = padlock_sc; 508ef0a6e20SPawel Jakub Dawidek struct padlock_session *ses; 509ef0a6e20SPawel Jakub Dawidek union padlock_cw *cw; 51064e18040SPawel Jakub Dawidek struct cryptodesc *crd, *enccrd, *maccrd; 511ef0a6e20SPawel Jakub Dawidek uint32_t *key; 512ef0a6e20SPawel Jakub Dawidek u_char *buf, *abuf; 51364e18040SPawel Jakub Dawidek int error = 0; 514ef0a6e20SPawel Jakub Dawidek 515bb348210SPawel Jakub Dawidek enccrd = maccrd = NULL; 516ef0a6e20SPawel Jakub Dawidek buf = NULL; 517bb348210SPawel Jakub Dawidek 51864e18040SPawel Jakub Dawidek if (crp == NULL || crp->crp_callback == NULL || crp->crp_desc == NULL) { 51964e18040SPawel Jakub Dawidek error = EINVAL; 520ef0a6e20SPawel Jakub Dawidek goto out; 521ef0a6e20SPawel Jakub Dawidek } 52264e18040SPawel Jakub Dawidek 52364e18040SPawel Jakub Dawidek for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) { 52464e18040SPawel Jakub Dawidek switch (crd->crd_alg) { 52564e18040SPawel Jakub Dawidek case CRYPTO_NULL_HMAC: 52664e18040SPawel Jakub Dawidek case CRYPTO_MD5_HMAC: 52764e18040SPawel Jakub Dawidek case CRYPTO_SHA1_HMAC: 52864e18040SPawel Jakub Dawidek case CRYPTO_RIPEMD160_HMAC: 52964e18040SPawel Jakub Dawidek case CRYPTO_SHA2_256_HMAC: 53064e18040SPawel Jakub Dawidek case CRYPTO_SHA2_384_HMAC: 53164e18040SPawel Jakub Dawidek case CRYPTO_SHA2_512_HMAC: 53264e18040SPawel Jakub Dawidek if (maccrd != NULL) { 53364e18040SPawel Jakub Dawidek error = EINVAL; 534ef0a6e20SPawel Jakub Dawidek goto out; 535ef0a6e20SPawel Jakub Dawidek } 53664e18040SPawel Jakub Dawidek maccrd = crd; 53764e18040SPawel Jakub Dawidek break; 53864e18040SPawel Jakub Dawidek case CRYPTO_AES_CBC: 53964e18040SPawel Jakub Dawidek if (enccrd != NULL) { 54064e18040SPawel Jakub Dawidek error = EINVAL; 54164e18040SPawel Jakub Dawidek goto out; 54264e18040SPawel Jakub Dawidek } 54364e18040SPawel Jakub Dawidek enccrd = crd; 54464e18040SPawel Jakub Dawidek break; 54564e18040SPawel Jakub Dawidek default: 54664e18040SPawel Jakub Dawidek return (EINVAL); 54764e18040SPawel Jakub Dawidek } 54864e18040SPawel Jakub Dawidek } 54964e18040SPawel Jakub Dawidek if (enccrd == NULL || (enccrd->crd_len % AES_BLOCK_LEN) != 0) { 55064e18040SPawel Jakub Dawidek error = EINVAL; 551eb340a61SPawel Jakub Dawidek goto out; 552eb340a61SPawel Jakub Dawidek } 553ef0a6e20SPawel Jakub Dawidek 554ef0a6e20SPawel Jakub Dawidek mtx_lock(&sc->sc_sessions_mtx); 555ef0a6e20SPawel Jakub Dawidek TAILQ_FOREACH(ses, &sc->sc_sessions, ses_next) { 556ef0a6e20SPawel Jakub Dawidek if (ses->ses_id == (crp->crp_sid & 0xffffffff)) 557ef0a6e20SPawel Jakub Dawidek break; 558ef0a6e20SPawel Jakub Dawidek } 559ef0a6e20SPawel Jakub Dawidek mtx_unlock(&sc->sc_sessions_mtx); 560ef0a6e20SPawel Jakub Dawidek if (ses == NULL) { 56164e18040SPawel Jakub Dawidek error = EINVAL; 562ef0a6e20SPawel Jakub Dawidek goto out; 563ef0a6e20SPawel Jakub Dawidek } 564ef0a6e20SPawel Jakub Dawidek 56564e18040SPawel Jakub Dawidek buf = malloc(enccrd->crd_len + 16, M_DEVBUF, M_NOWAIT); 566ef0a6e20SPawel Jakub Dawidek if (buf == NULL) { 56764e18040SPawel Jakub Dawidek error = ENOMEM; 568ef0a6e20SPawel Jakub Dawidek goto out; 569ef0a6e20SPawel Jakub Dawidek } 57064e18040SPawel Jakub Dawidek /* Buffer has to be 16 bytes aligned. */ 571ef0a6e20SPawel Jakub Dawidek abuf = buf + 16 - ((uintptr_t)buf % 16); 572ef0a6e20SPawel Jakub Dawidek 57364e18040SPawel Jakub Dawidek if ((enccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0) 57464e18040SPawel Jakub Dawidek padlock_setup_enckey(ses, enccrd->crd_key, enccrd->crd_klen); 57564e18040SPawel Jakub Dawidek if (maccrd != NULL && (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0) 57664e18040SPawel Jakub Dawidek padlock_setup_mackey(ses, maccrd->crd_key, maccrd->crd_klen); 57764e18040SPawel Jakub Dawidek 578ef0a6e20SPawel Jakub Dawidek cw = &ses->ses_cw; 579ef0a6e20SPawel Jakub Dawidek cw->cw_filler0 = 0; 580ef0a6e20SPawel Jakub Dawidek cw->cw_filler1 = 0; 581ef0a6e20SPawel Jakub Dawidek cw->cw_filler2 = 0; 582ef0a6e20SPawel Jakub Dawidek cw->cw_filler3 = 0; 58364e18040SPawel Jakub Dawidek if ((enccrd->crd_flags & CRD_F_ENCRYPT) != 0) { 584ef0a6e20SPawel Jakub Dawidek cw->cw_direction = PADLOCK_DIRECTION_ENCRYPT; 585ef0a6e20SPawel Jakub Dawidek key = ses->ses_ekey; 58664e18040SPawel Jakub Dawidek if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0) 58764e18040SPawel Jakub Dawidek bcopy(enccrd->crd_iv, ses->ses_iv, 16); 588ef0a6e20SPawel Jakub Dawidek 58964e18040SPawel Jakub Dawidek if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) { 59064e18040SPawel Jakub Dawidek crypto_copyback(crp->crp_flags, crp->crp_buf, 59164e18040SPawel Jakub Dawidek enccrd->crd_inject, AES_BLOCK_LEN, ses->ses_iv); 592ef0a6e20SPawel Jakub Dawidek } 593ef0a6e20SPawel Jakub Dawidek } else { 594ef0a6e20SPawel Jakub Dawidek cw->cw_direction = PADLOCK_DIRECTION_DECRYPT; 595ef0a6e20SPawel Jakub Dawidek key = ses->ses_dkey; 59664e18040SPawel Jakub Dawidek if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0) 59764e18040SPawel Jakub Dawidek bcopy(enccrd->crd_iv, ses->ses_iv, AES_BLOCK_LEN); 598ef0a6e20SPawel Jakub Dawidek else { 59964e18040SPawel Jakub Dawidek crypto_copydata(crp->crp_flags, crp->crp_buf, 60064e18040SPawel Jakub Dawidek enccrd->crd_inject, AES_BLOCK_LEN, ses->ses_iv); 601ef0a6e20SPawel Jakub Dawidek } 602ef0a6e20SPawel Jakub Dawidek } 603ef0a6e20SPawel Jakub Dawidek 60464e18040SPawel Jakub Dawidek /* Perform data authentication if requested before encryption. */ 60564e18040SPawel Jakub Dawidek if (maccrd != NULL && maccrd->crd_next == enccrd) { 60664e18040SPawel Jakub Dawidek error = padlock_authcompute(ses, maccrd, crp->crp_buf, 60764e18040SPawel Jakub Dawidek crp->crp_flags); 60864e18040SPawel Jakub Dawidek if (error != 0) 60964e18040SPawel Jakub Dawidek goto out; 610ef0a6e20SPawel Jakub Dawidek } 611ef0a6e20SPawel Jakub Dawidek 61264e18040SPawel Jakub Dawidek crypto_copydata(crp->crp_flags, crp->crp_buf, enccrd->crd_skip, 61364e18040SPawel Jakub Dawidek enccrd->crd_len, abuf); 614ef0a6e20SPawel Jakub Dawidek 61564e18040SPawel Jakub Dawidek padlock_cbc(abuf, abuf, enccrd->crd_len / 16, key, cw, ses->ses_iv); 61664e18040SPawel Jakub Dawidek 61764e18040SPawel Jakub Dawidek crypto_copyback(crp->crp_flags, crp->crp_buf, enccrd->crd_skip, 61864e18040SPawel Jakub Dawidek enccrd->crd_len, abuf); 61964e18040SPawel Jakub Dawidek 62064e18040SPawel Jakub Dawidek /* Perform data authentication if requested after encryption. */ 62164e18040SPawel Jakub Dawidek if (maccrd != NULL && enccrd->crd_next == maccrd) { 62264e18040SPawel Jakub Dawidek error = padlock_authcompute(ses, maccrd, crp->crp_buf, 62364e18040SPawel Jakub Dawidek crp->crp_flags); 62464e18040SPawel Jakub Dawidek if (error != 0) 62564e18040SPawel Jakub Dawidek goto out; 626ef0a6e20SPawel Jakub Dawidek } 627ef0a6e20SPawel Jakub Dawidek 628ef0a6e20SPawel Jakub Dawidek /* copy out last block for use as next session IV */ 62964e18040SPawel Jakub Dawidek if ((enccrd->crd_flags & CRD_F_ENCRYPT) != 0) { 63064e18040SPawel Jakub Dawidek crypto_copydata(crp->crp_flags, crp->crp_buf, 63164e18040SPawel Jakub Dawidek enccrd->crd_skip + enccrd->crd_len - AES_BLOCK_LEN, 63264e18040SPawel Jakub Dawidek AES_BLOCK_LEN, ses->ses_iv); 633ef0a6e20SPawel Jakub Dawidek } 634ef0a6e20SPawel Jakub Dawidek 635ef0a6e20SPawel Jakub Dawidek out: 636ef0a6e20SPawel Jakub Dawidek if (buf != NULL) { 63764e18040SPawel Jakub Dawidek bzero(buf, enccrd->crd_len + 16); 638ef0a6e20SPawel Jakub Dawidek free(buf, M_DEVBUF); 639ef0a6e20SPawel Jakub Dawidek } 64064e18040SPawel Jakub Dawidek crp->crp_etype = error; 641ef0a6e20SPawel Jakub Dawidek crypto_done(crp); 64264e18040SPawel Jakub Dawidek return (error); 643ef0a6e20SPawel Jakub Dawidek } 644ef0a6e20SPawel Jakub Dawidek 645ef0a6e20SPawel Jakub Dawidek static int 646ef0a6e20SPawel Jakub Dawidek padlock_modevent(module_t mod, int type, void *unused __unused) 647ef0a6e20SPawel Jakub Dawidek { 648ef0a6e20SPawel Jakub Dawidek int error; 649ef0a6e20SPawel Jakub Dawidek 650ef0a6e20SPawel Jakub Dawidek error = EOPNOTSUPP; 651ef0a6e20SPawel Jakub Dawidek switch (type) { 652ef0a6e20SPawel Jakub Dawidek case MOD_LOAD: 653ef0a6e20SPawel Jakub Dawidek error = padlock_init(); 654ef0a6e20SPawel Jakub Dawidek break; 655ef0a6e20SPawel Jakub Dawidek case MOD_UNLOAD: 656ef0a6e20SPawel Jakub Dawidek error = padlock_destroy(); 657ef0a6e20SPawel Jakub Dawidek break; 658ef0a6e20SPawel Jakub Dawidek } 659ef0a6e20SPawel Jakub Dawidek return (error); 660ef0a6e20SPawel Jakub Dawidek } 661ef0a6e20SPawel Jakub Dawidek 662ef0a6e20SPawel Jakub Dawidek static moduledata_t padlock_mod = { 663ef0a6e20SPawel Jakub Dawidek "padlock", 664ef0a6e20SPawel Jakub Dawidek padlock_modevent, 665ef0a6e20SPawel Jakub Dawidek 0 666ef0a6e20SPawel Jakub Dawidek }; 667ef0a6e20SPawel Jakub Dawidek DECLARE_MODULE(padlock, padlock_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); 668ef0a6e20SPawel Jakub Dawidek MODULE_VERSION(padlock, 1); 669ef0a6e20SPawel Jakub Dawidek MODULE_DEPEND(padlock, crypto, 1, 1, 1); 670