xref: /freebsd/sys/crypto/via/padlock.c (revision 4fd58e10)
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