1*ee55792fSriastradh /* $NetBSD: cryptosoft.c,v 1.64 2022/05/22 11:39:27 riastradh Exp $ */
2cdfce9ceSjonathan /* $FreeBSD: src/sys/opencrypto/cryptosoft.c,v 1.2.2.1 2002/11/21 23:34:23 sam Exp $ */
3cdfce9ceSjonathan /* $OpenBSD: cryptosoft.c,v 1.35 2002/04/26 08:43:50 deraadt Exp $ */
4cdfce9ceSjonathan
5cdfce9ceSjonathan /*
6cdfce9ceSjonathan * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
7cdfce9ceSjonathan *
8cdfce9ceSjonathan * This code was written by Angelos D. Keromytis in Athens, Greece, in
9cdfce9ceSjonathan * February 2000. Network Security Technologies Inc. (NSTI) kindly
10cdfce9ceSjonathan * supported the development of this code.
11cdfce9ceSjonathan *
12cdfce9ceSjonathan * Copyright (c) 2000, 2001 Angelos D. Keromytis
13cdfce9ceSjonathan *
14cdfce9ceSjonathan * Permission to use, copy, and modify this software with or without fee
15cdfce9ceSjonathan * is hereby granted, provided that this entire notice is included in
16cdfce9ceSjonathan * all source code copies of any software which is or includes a copy or
17cdfce9ceSjonathan * modification of this software.
18cdfce9ceSjonathan *
19cdfce9ceSjonathan * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
20cdfce9ceSjonathan * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
21cdfce9ceSjonathan * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
22cdfce9ceSjonathan * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
23cdfce9ceSjonathan * PURPOSE.
24cdfce9ceSjonathan */
25cdfce9ceSjonathan
26cdfce9ceSjonathan #include <sys/cdefs.h>
27*ee55792fSriastradh __KERNEL_RCSID(0, "$NetBSD: cryptosoft.c,v 1.64 2022/05/22 11:39:27 riastradh Exp $");
28cdfce9ceSjonathan
29cdfce9ceSjonathan #include <sys/param.h>
30cdfce9ceSjonathan #include <sys/systm.h>
313ca2c3f4Sknakahara #include <sys/kmem.h>
32cdfce9ceSjonathan #include <sys/mbuf.h>
33cdfce9ceSjonathan #include <sys/sysctl.h>
34cdfce9ceSjonathan #include <sys/errno.h>
359305dd35Schristos #include <sys/cprng.h>
362dd4f4d9Spgoyette #include <sys/module.h>
372dd4f4d9Spgoyette #include <sys/device.h>
38b2fb48e9Sjonathan
392dd4f4d9Spgoyette #ifdef _KERNEL_OPT
40e5bd2a12Stls #include "opt_ocf.h"
412dd4f4d9Spgoyette #endif
422dd4f4d9Spgoyette
43cdfce9ceSjonathan #include <opencrypto/cryptodev.h>
44cdfce9ceSjonathan #include <opencrypto/cryptosoft.h>
45cdfce9ceSjonathan #include <opencrypto/xform.h>
46cdfce9ceSjonathan
477bc6d90cSthorpej #include <opencrypto/cryptosoft_xform.c>
48cdfce9ceSjonathan
49e7ae23fdSchristos #include "ioconf.h"
50e7ae23fdSchristos
517bc6d90cSthorpej union authctx {
527bc6d90cSthorpej MD5_CTX md5ctx;
537bc6d90cSthorpej SHA1_CTX sha1ctx;
547bc6d90cSthorpej RMD160_CTX rmd160ctx;
557bc6d90cSthorpej SHA256_CTX sha256ctx;
567bc6d90cSthorpej SHA384_CTX sha384ctx;
577bc6d90cSthorpej SHA512_CTX sha512ctx;
58ebc232a5Sdrochner aesxcbc_ctx aesxcbcctx;
590a8dabdaSdrochner AES_GMAC_CTX aesgmacctx;
60cdfce9ceSjonathan };
61cdfce9ceSjonathan
62cdfce9ceSjonathan struct swcr_data **swcr_sessions = NULL;
63cdfce9ceSjonathan u_int32_t swcr_sesnum = 0;
64cdfce9ceSjonathan int32_t swcr_id = -1;
65cdfce9ceSjonathan
66cdfce9ceSjonathan #define COPYBACK(x, a, b, c, d) \
67cdfce9ceSjonathan (x) == CRYPTO_BUF_MBUF ? m_copyback((struct mbuf *)a,b,c,d) \
68cdfce9ceSjonathan : cuio_copyback((struct uio *)a,b,c,d)
69cdfce9ceSjonathan #define COPYDATA(x, a, b, c, d) \
70cdfce9ceSjonathan (x) == CRYPTO_BUF_MBUF ? m_copydata((struct mbuf *)a,b,c,d) \
71cdfce9ceSjonathan : cuio_copydata((struct uio *)a,b,c,d)
72cdfce9ceSjonathan
732e4e5505Sdrochner static int swcr_encdec(struct cryptodesc *, const struct swcr_data *, void *, int);
742e4e5505Sdrochner static int swcr_compdec(struct cryptodesc *, const struct swcr_data *, void *, int, int *);
750a8dabdaSdrochner static int swcr_combined(struct cryptop *, int);
76cdfce9ceSjonathan static int swcr_process(void *, struct cryptop *, int);
77cdfce9ceSjonathan static int swcr_newsession(void *, u_int32_t *, struct cryptoini *);
78*ee55792fSriastradh static void swcr_freesession(void *, u_int64_t);
79cfd5cbf4Sknakahara static void swcr_freesession_internal(struct swcr_data *);
80cdfce9ceSjonathan
8180c73109Sknakahara static int swcryptoattach_internal(void);
8280c73109Sknakahara
83cdfce9ceSjonathan /*
84cdfce9ceSjonathan * Apply a symmetric encryption/decryption algorithm.
85cdfce9ceSjonathan */
86cdfce9ceSjonathan static int
swcr_encdec(struct cryptodesc * crd,const struct swcr_data * sw,void * bufv,int outtype)872e4e5505Sdrochner swcr_encdec(struct cryptodesc *crd, const struct swcr_data *sw, void *bufv,
88cdfce9ceSjonathan int outtype)
89cdfce9ceSjonathan {
9053524e44Schristos char *buf = bufv;
91cdfce9ceSjonathan unsigned char iv[EALG_MAX_BLOCK_LEN], blk[EALG_MAX_BLOCK_LEN], *idat;
92cdfce9ceSjonathan unsigned char *ivp, piv[EALG_MAX_BLOCK_LEN];
937bc6d90cSthorpej const struct swcr_enc_xform *exf;
945fafa9c4Sdrochner int i, k, j, blks, ivlen;
95cdfce9ceSjonathan int count, ind;
96cdfce9ceSjonathan
97cdfce9ceSjonathan exf = sw->sw_exf;
987bc6d90cSthorpej blks = exf->enc_xform->blocksize;
995fafa9c4Sdrochner ivlen = exf->enc_xform->ivsize;
1005fafa9c4Sdrochner KASSERT(exf->reinit ? ivlen <= blks : ivlen == blks);
101cdfce9ceSjonathan
102cdfce9ceSjonathan /* Check for non-padded data */
103cdfce9ceSjonathan if (crd->crd_len % blks)
104cdfce9ceSjonathan return EINVAL;
105cdfce9ceSjonathan
106cdfce9ceSjonathan /* Initialize the IV */
107cdfce9ceSjonathan if (crd->crd_flags & CRD_F_ENCRYPT) {
108cdfce9ceSjonathan /* IV explicitly provided ? */
109a8250350Sdrochner if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
1105fafa9c4Sdrochner memcpy(iv, crd->crd_iv, ivlen);
111a8250350Sdrochner if (exf->reinit)
112a8250350Sdrochner exf->reinit(sw->sw_kschedule, iv, 0);
113a8250350Sdrochner } else if (exf->reinit) {
114a8250350Sdrochner exf->reinit(sw->sw_kschedule, 0, iv);
115a8250350Sdrochner } else {
116f69a480bSriastradh cprng_fast(iv, EALG_MAX_BLOCK_LEN);
117cdfce9ceSjonathan }
118cdfce9ceSjonathan
119cdfce9ceSjonathan /* Do we need to write the IV */
120cdfce9ceSjonathan if (!(crd->crd_flags & CRD_F_IV_PRESENT)) {
1215fafa9c4Sdrochner COPYBACK(outtype, buf, crd->crd_inject, ivlen, iv);
122cdfce9ceSjonathan }
123cdfce9ceSjonathan
124cdfce9ceSjonathan } else { /* Decryption */
125cdfce9ceSjonathan /* IV explicitly provided ? */
126cdfce9ceSjonathan if (crd->crd_flags & CRD_F_IV_EXPLICIT)
1275fafa9c4Sdrochner memcpy(iv, crd->crd_iv, ivlen);
128cdfce9ceSjonathan else {
129cdfce9ceSjonathan /* Get IV off buf */
1305fafa9c4Sdrochner COPYDATA(outtype, buf, crd->crd_inject, ivlen, iv);
131cdfce9ceSjonathan }
132a8250350Sdrochner if (exf->reinit)
133a8250350Sdrochner exf->reinit(sw->sw_kschedule, iv, 0);
134cdfce9ceSjonathan }
135cdfce9ceSjonathan
136cdfce9ceSjonathan ivp = iv;
137cdfce9ceSjonathan
138cdfce9ceSjonathan if (outtype == CRYPTO_BUF_CONTIG) {
1395fafa9c4Sdrochner if (exf->reinit) {
1405fafa9c4Sdrochner for (i = crd->crd_skip;
1415fafa9c4Sdrochner i < crd->crd_skip + crd->crd_len; i += blks) {
142cdfce9ceSjonathan if (crd->crd_flags & CRD_F_ENCRYPT) {
1435fafa9c4Sdrochner exf->encrypt(sw->sw_kschedule, buf + i);
1445fafa9c4Sdrochner } else {
1455fafa9c4Sdrochner exf->decrypt(sw->sw_kschedule, buf + i);
1465fafa9c4Sdrochner }
1475fafa9c4Sdrochner }
1485fafa9c4Sdrochner } else if (crd->crd_flags & CRD_F_ENCRYPT) {
149cdfce9ceSjonathan for (i = crd->crd_skip;
150cdfce9ceSjonathan i < crd->crd_skip + crd->crd_len; i += blks) {
151cdfce9ceSjonathan /* XOR with the IV/previous block, as appropriate. */
152cdfce9ceSjonathan if (i == crd->crd_skip)
153cdfce9ceSjonathan for (k = 0; k < blks; k++)
154cdfce9ceSjonathan buf[i + k] ^= ivp[k];
155cdfce9ceSjonathan else
156cdfce9ceSjonathan for (k = 0; k < blks; k++)
157cdfce9ceSjonathan buf[i + k] ^= buf[i + k - blks];
158cdfce9ceSjonathan exf->encrypt(sw->sw_kschedule, buf + i);
159cdfce9ceSjonathan }
160cdfce9ceSjonathan } else { /* Decrypt */
161cdfce9ceSjonathan /*
162cdfce9ceSjonathan * Start at the end, so we don't need to keep the encrypted
163cdfce9ceSjonathan * block as the IV for the next block.
164cdfce9ceSjonathan */
165cdfce9ceSjonathan for (i = crd->crd_skip + crd->crd_len - blks;
166cdfce9ceSjonathan i >= crd->crd_skip; i -= blks) {
167cdfce9ceSjonathan exf->decrypt(sw->sw_kschedule, buf + i);
168cdfce9ceSjonathan
169cdfce9ceSjonathan /* XOR with the IV/previous block, as appropriate */
170cdfce9ceSjonathan if (i == crd->crd_skip)
171cdfce9ceSjonathan for (k = 0; k < blks; k++)
172cdfce9ceSjonathan buf[i + k] ^= ivp[k];
173cdfce9ceSjonathan else
174cdfce9ceSjonathan for (k = 0; k < blks; k++)
175cdfce9ceSjonathan buf[i + k] ^= buf[i + k - blks];
176cdfce9ceSjonathan }
177cdfce9ceSjonathan }
178cdfce9ceSjonathan
179cdfce9ceSjonathan return 0;
180cdfce9ceSjonathan } else if (outtype == CRYPTO_BUF_MBUF) {
181cdfce9ceSjonathan struct mbuf *m = (struct mbuf *) buf;
182cdfce9ceSjonathan
183cdfce9ceSjonathan /* Find beginning of data */
184cdfce9ceSjonathan m = m_getptr(m, crd->crd_skip, &k);
185cdfce9ceSjonathan if (m == NULL)
186cdfce9ceSjonathan return EINVAL;
187cdfce9ceSjonathan
188cdfce9ceSjonathan i = crd->crd_len;
189cdfce9ceSjonathan
190cdfce9ceSjonathan while (i > 0) {
191cdfce9ceSjonathan /*
192cdfce9ceSjonathan * If there's insufficient data at the end of
193cdfce9ceSjonathan * an mbuf, we have to do some copying.
194cdfce9ceSjonathan */
195cdfce9ceSjonathan if (m->m_len < k + blks && m->m_len != k) {
196cdfce9ceSjonathan m_copydata(m, k, blks, blk);
197cdfce9ceSjonathan
198cdfce9ceSjonathan /* Actual encryption/decryption */
1995fafa9c4Sdrochner if (exf->reinit) {
200cdfce9ceSjonathan if (crd->crd_flags & CRD_F_ENCRYPT) {
2015fafa9c4Sdrochner exf->encrypt(sw->sw_kschedule,
2025fafa9c4Sdrochner blk);
2035fafa9c4Sdrochner } else {
2045fafa9c4Sdrochner exf->decrypt(sw->sw_kschedule,
2055fafa9c4Sdrochner blk);
2065fafa9c4Sdrochner }
2075fafa9c4Sdrochner } else if (crd->crd_flags & CRD_F_ENCRYPT) {
208cdfce9ceSjonathan /* XOR with previous block */
209cdfce9ceSjonathan for (j = 0; j < blks; j++)
210cdfce9ceSjonathan blk[j] ^= ivp[j];
211cdfce9ceSjonathan
212cdfce9ceSjonathan exf->encrypt(sw->sw_kschedule, blk);
213cdfce9ceSjonathan
214cdfce9ceSjonathan /*
215cdfce9ceSjonathan * Keep encrypted block for XOR'ing
216cdfce9ceSjonathan * with next block
217cdfce9ceSjonathan */
218e2cb8590Scegger memcpy(iv, blk, blks);
219cdfce9ceSjonathan ivp = iv;
220cdfce9ceSjonathan } else { /* decrypt */
221cdfce9ceSjonathan /*
222cdfce9ceSjonathan * Keep encrypted block for XOR'ing
223cdfce9ceSjonathan * with next block
224cdfce9ceSjonathan */
225cdfce9ceSjonathan if (ivp == iv)
226e2cb8590Scegger memcpy(piv, blk, blks);
227cdfce9ceSjonathan else
228e2cb8590Scegger memcpy(iv, blk, blks);
229cdfce9ceSjonathan
230cdfce9ceSjonathan exf->decrypt(sw->sw_kschedule, blk);
231cdfce9ceSjonathan
232cdfce9ceSjonathan /* XOR with previous block */
233cdfce9ceSjonathan for (j = 0; j < blks; j++)
234cdfce9ceSjonathan blk[j] ^= ivp[j];
235cdfce9ceSjonathan
236cdfce9ceSjonathan if (ivp == iv)
237e2cb8590Scegger memcpy(iv, piv, blks);
238cdfce9ceSjonathan else
239cdfce9ceSjonathan ivp = iv;
240cdfce9ceSjonathan }
241cdfce9ceSjonathan
242cdfce9ceSjonathan /* Copy back decrypted block */
243cdfce9ceSjonathan m_copyback(m, k, blks, blk);
244cdfce9ceSjonathan
245cdfce9ceSjonathan /* Advance pointer */
246cdfce9ceSjonathan m = m_getptr(m, k + blks, &k);
247cdfce9ceSjonathan if (m == NULL)
248cdfce9ceSjonathan return EINVAL;
249cdfce9ceSjonathan
250cdfce9ceSjonathan i -= blks;
251cdfce9ceSjonathan
252cdfce9ceSjonathan /* Could be done... */
253cdfce9ceSjonathan if (i == 0)
254cdfce9ceSjonathan break;
255cdfce9ceSjonathan }
256cdfce9ceSjonathan
257cdfce9ceSjonathan /* Skip possibly empty mbufs */
258cdfce9ceSjonathan if (k == m->m_len) {
259cdfce9ceSjonathan for (m = m->m_next; m && m->m_len == 0;
260cdfce9ceSjonathan m = m->m_next)
261cdfce9ceSjonathan ;
262cdfce9ceSjonathan k = 0;
263cdfce9ceSjonathan }
264cdfce9ceSjonathan
265cdfce9ceSjonathan /* Sanity check */
266cdfce9ceSjonathan if (m == NULL)
267cdfce9ceSjonathan return EINVAL;
268cdfce9ceSjonathan
269cdfce9ceSjonathan /*
270cdfce9ceSjonathan * Warning: idat may point to garbage here, but
271cdfce9ceSjonathan * we only use it in the while() loop, only if
272cdfce9ceSjonathan * there are indeed enough data.
273cdfce9ceSjonathan */
274cdfce9ceSjonathan idat = mtod(m, unsigned char *) + k;
275cdfce9ceSjonathan
276cdfce9ceSjonathan while (m->m_len >= k + blks && i > 0) {
2775fafa9c4Sdrochner if (exf->reinit) {
278cdfce9ceSjonathan if (crd->crd_flags & CRD_F_ENCRYPT) {
2795fafa9c4Sdrochner exf->encrypt(sw->sw_kschedule,
2805fafa9c4Sdrochner idat);
2815fafa9c4Sdrochner } else {
2825fafa9c4Sdrochner exf->decrypt(sw->sw_kschedule,
2835fafa9c4Sdrochner idat);
2845fafa9c4Sdrochner }
2855fafa9c4Sdrochner } else if (crd->crd_flags & CRD_F_ENCRYPT) {
286cdfce9ceSjonathan /* XOR with previous block/IV */
287cdfce9ceSjonathan for (j = 0; j < blks; j++)
288cdfce9ceSjonathan idat[j] ^= ivp[j];
289cdfce9ceSjonathan
290cdfce9ceSjonathan exf->encrypt(sw->sw_kschedule, idat);
291cdfce9ceSjonathan ivp = idat;
292cdfce9ceSjonathan } else { /* decrypt */
293cdfce9ceSjonathan /*
294cdfce9ceSjonathan * Keep encrypted block to be used
295cdfce9ceSjonathan * in next block's processing.
296cdfce9ceSjonathan */
297cdfce9ceSjonathan if (ivp == iv)
298e2cb8590Scegger memcpy(piv, idat, blks);
299cdfce9ceSjonathan else
300e2cb8590Scegger memcpy(iv, idat, blks);
301cdfce9ceSjonathan
302cdfce9ceSjonathan exf->decrypt(sw->sw_kschedule, idat);
303cdfce9ceSjonathan
304cdfce9ceSjonathan /* XOR with previous block/IV */
305cdfce9ceSjonathan for (j = 0; j < blks; j++)
306cdfce9ceSjonathan idat[j] ^= ivp[j];
307cdfce9ceSjonathan
308cdfce9ceSjonathan if (ivp == iv)
309e2cb8590Scegger memcpy(iv, piv, blks);
310cdfce9ceSjonathan else
311cdfce9ceSjonathan ivp = iv;
312cdfce9ceSjonathan }
313cdfce9ceSjonathan
314cdfce9ceSjonathan idat += blks;
315cdfce9ceSjonathan k += blks;
316cdfce9ceSjonathan i -= blks;
317cdfce9ceSjonathan }
318cdfce9ceSjonathan }
319cdfce9ceSjonathan
320cdfce9ceSjonathan return 0; /* Done with mbuf encryption/decryption */
321cdfce9ceSjonathan } else if (outtype == CRYPTO_BUF_IOV) {
322cdfce9ceSjonathan struct uio *uio = (struct uio *) buf;
323cdfce9ceSjonathan
324cdfce9ceSjonathan /* Find beginning of data */
325cdfce9ceSjonathan count = crd->crd_skip;
326cdfce9ceSjonathan ind = cuio_getptr(uio, count, &k);
327cdfce9ceSjonathan if (ind == -1)
328cdfce9ceSjonathan return EINVAL;
329cdfce9ceSjonathan
330cdfce9ceSjonathan i = crd->crd_len;
331cdfce9ceSjonathan
332cdfce9ceSjonathan while (i > 0) {
333cdfce9ceSjonathan /*
334cdfce9ceSjonathan * If there's insufficient data at the end,
335cdfce9ceSjonathan * we have to do some copying.
336cdfce9ceSjonathan */
337cdfce9ceSjonathan if (uio->uio_iov[ind].iov_len < k + blks &&
338cdfce9ceSjonathan uio->uio_iov[ind].iov_len != k) {
339cdfce9ceSjonathan cuio_copydata(uio, k, blks, blk);
340cdfce9ceSjonathan
341cdfce9ceSjonathan /* Actual encryption/decryption */
3425fafa9c4Sdrochner if (exf->reinit) {
343cdfce9ceSjonathan if (crd->crd_flags & CRD_F_ENCRYPT) {
3445fafa9c4Sdrochner exf->encrypt(sw->sw_kschedule,
3455fafa9c4Sdrochner blk);
3465fafa9c4Sdrochner } else {
3475fafa9c4Sdrochner exf->decrypt(sw->sw_kschedule,
3485fafa9c4Sdrochner blk);
3495fafa9c4Sdrochner }
3505fafa9c4Sdrochner } else if (crd->crd_flags & CRD_F_ENCRYPT) {
351cdfce9ceSjonathan /* XOR with previous block */
352cdfce9ceSjonathan for (j = 0; j < blks; j++)
353cdfce9ceSjonathan blk[j] ^= ivp[j];
354cdfce9ceSjonathan
355cdfce9ceSjonathan exf->encrypt(sw->sw_kschedule, blk);
356cdfce9ceSjonathan
357cdfce9ceSjonathan /*
358cdfce9ceSjonathan * Keep encrypted block for XOR'ing
359cdfce9ceSjonathan * with next block
360cdfce9ceSjonathan */
361e2cb8590Scegger memcpy(iv, blk, blks);
362cdfce9ceSjonathan ivp = iv;
363cdfce9ceSjonathan } else { /* decrypt */
364cdfce9ceSjonathan /*
365cdfce9ceSjonathan * Keep encrypted block for XOR'ing
366cdfce9ceSjonathan * with next block
367cdfce9ceSjonathan */
368cdfce9ceSjonathan if (ivp == iv)
369e2cb8590Scegger memcpy(piv, blk, blks);
370cdfce9ceSjonathan else
371e2cb8590Scegger memcpy(iv, blk, blks);
372cdfce9ceSjonathan
373cdfce9ceSjonathan exf->decrypt(sw->sw_kschedule, blk);
374cdfce9ceSjonathan
375cdfce9ceSjonathan /* XOR with previous block */
376cdfce9ceSjonathan for (j = 0; j < blks; j++)
377cdfce9ceSjonathan blk[j] ^= ivp[j];
378cdfce9ceSjonathan
379cdfce9ceSjonathan if (ivp == iv)
380e2cb8590Scegger memcpy(iv, piv, blks);
381cdfce9ceSjonathan else
382cdfce9ceSjonathan ivp = iv;
383cdfce9ceSjonathan }
384cdfce9ceSjonathan
385cdfce9ceSjonathan /* Copy back decrypted block */
386cdfce9ceSjonathan cuio_copyback(uio, k, blks, blk);
387cdfce9ceSjonathan
388cdfce9ceSjonathan count += blks;
389cdfce9ceSjonathan
390cdfce9ceSjonathan /* Advance pointer */
391cdfce9ceSjonathan ind = cuio_getptr(uio, count, &k);
392cdfce9ceSjonathan if (ind == -1)
393cdfce9ceSjonathan return (EINVAL);
394cdfce9ceSjonathan
395cdfce9ceSjonathan i -= blks;
396cdfce9ceSjonathan
397cdfce9ceSjonathan /* Could be done... */
398cdfce9ceSjonathan if (i == 0)
399cdfce9ceSjonathan break;
400cdfce9ceSjonathan }
401cdfce9ceSjonathan
402cdfce9ceSjonathan /*
403cdfce9ceSjonathan * Warning: idat may point to garbage here, but
404cdfce9ceSjonathan * we only use it in the while() loop, only if
405cdfce9ceSjonathan * there are indeed enough data.
406cdfce9ceSjonathan */
40753524e44Schristos idat = ((char *)uio->uio_iov[ind].iov_base) + k;
408cdfce9ceSjonathan
409cdfce9ceSjonathan while (uio->uio_iov[ind].iov_len >= k + blks &&
410cdfce9ceSjonathan i > 0) {
4115fafa9c4Sdrochner if (exf->reinit) {
412cdfce9ceSjonathan if (crd->crd_flags & CRD_F_ENCRYPT) {
4135fafa9c4Sdrochner exf->encrypt(sw->sw_kschedule,
4145fafa9c4Sdrochner idat);
4155fafa9c4Sdrochner } else {
4165fafa9c4Sdrochner exf->decrypt(sw->sw_kschedule,
4175fafa9c4Sdrochner idat);
4185fafa9c4Sdrochner }
4195fafa9c4Sdrochner } else if (crd->crd_flags & CRD_F_ENCRYPT) {
420cdfce9ceSjonathan /* XOR with previous block/IV */
421cdfce9ceSjonathan for (j = 0; j < blks; j++)
422cdfce9ceSjonathan idat[j] ^= ivp[j];
423cdfce9ceSjonathan
424cdfce9ceSjonathan exf->encrypt(sw->sw_kschedule, idat);
425cdfce9ceSjonathan ivp = idat;
426cdfce9ceSjonathan } else { /* decrypt */
427cdfce9ceSjonathan /*
428cdfce9ceSjonathan * Keep encrypted block to be used
429cdfce9ceSjonathan * in next block's processing.
430cdfce9ceSjonathan */
431cdfce9ceSjonathan if (ivp == iv)
432e2cb8590Scegger memcpy(piv, idat, blks);
433cdfce9ceSjonathan else
434e2cb8590Scegger memcpy(iv, idat, blks);
435cdfce9ceSjonathan
436cdfce9ceSjonathan exf->decrypt(sw->sw_kschedule, idat);
437cdfce9ceSjonathan
438cdfce9ceSjonathan /* XOR with previous block/IV */
439cdfce9ceSjonathan for (j = 0; j < blks; j++)
440cdfce9ceSjonathan idat[j] ^= ivp[j];
441cdfce9ceSjonathan
442cdfce9ceSjonathan if (ivp == iv)
443e2cb8590Scegger memcpy(iv, piv, blks);
444cdfce9ceSjonathan else
445cdfce9ceSjonathan ivp = iv;
446cdfce9ceSjonathan }
447cdfce9ceSjonathan
448cdfce9ceSjonathan idat += blks;
449cdfce9ceSjonathan count += blks;
450cdfce9ceSjonathan k += blks;
451cdfce9ceSjonathan i -= blks;
452cdfce9ceSjonathan }
453cdfce9ceSjonathan }
454cdfce9ceSjonathan return 0; /* Done with mbuf encryption/decryption */
455cdfce9ceSjonathan }
456cdfce9ceSjonathan
457cdfce9ceSjonathan /* Unreachable */
458cdfce9ceSjonathan return EINVAL;
459cdfce9ceSjonathan }
460cdfce9ceSjonathan
461cdfce9ceSjonathan /*
462cdfce9ceSjonathan * Compute keyed-hash authenticator.
463cdfce9ceSjonathan */
464c339e558Sdaniel int
swcr_authcompute(struct cryptop * crp,struct cryptodesc * crd,const struct swcr_data * sw,void * buf,int outtype)465cdfce9ceSjonathan swcr_authcompute(struct cryptop *crp, struct cryptodesc *crd,
4662e4e5505Sdrochner const struct swcr_data *sw, void *buf, int outtype)
467cdfce9ceSjonathan {
468cdfce9ceSjonathan unsigned char aalg[AALG_MAX_RESULT_LEN];
4697bc6d90cSthorpej const struct swcr_auth_hash *axf;
470cdfce9ceSjonathan union authctx ctx;
471cdfce9ceSjonathan int err;
472cdfce9ceSjonathan
473cdfce9ceSjonathan if (sw->sw_ictx == 0)
474cdfce9ceSjonathan return EINVAL;
475cdfce9ceSjonathan
476cdfce9ceSjonathan axf = sw->sw_axf;
477cdfce9ceSjonathan
4789f36e765Sdrochner memcpy(&ctx, sw->sw_ictx, axf->ctxsize);
479cdfce9ceSjonathan
480cdfce9ceSjonathan switch (outtype) {
481cdfce9ceSjonathan case CRYPTO_BUF_CONTIG:
48253524e44Schristos axf->Update(&ctx, (char *)buf + crd->crd_skip, crd->crd_len);
483cdfce9ceSjonathan break;
484cdfce9ceSjonathan case CRYPTO_BUF_MBUF:
485cdfce9ceSjonathan err = m_apply((struct mbuf *) buf, crd->crd_skip, crd->crd_len,
4864ce1278aSchristos (int (*)(void*, void *, unsigned int))(void *)axf->Update,
48753524e44Schristos (void *) &ctx);
488cdfce9ceSjonathan if (err)
489cdfce9ceSjonathan return err;
490cdfce9ceSjonathan break;
491cdfce9ceSjonathan case CRYPTO_BUF_IOV:
492de6bc09eSjonathan err = cuio_apply((struct uio *) buf, crd->crd_skip,
493de6bc09eSjonathan crd->crd_len,
4944ce1278aSchristos (int (*)(void *, void *, unsigned int))(void *)axf->Update,
49553524e44Schristos (void *) &ctx);
496de6bc09eSjonathan if (err) {
497de6bc09eSjonathan return err;
498de6bc09eSjonathan }
499de6bc09eSjonathan break;
500cdfce9ceSjonathan default:
501cdfce9ceSjonathan return EINVAL;
502cdfce9ceSjonathan }
503cdfce9ceSjonathan
504cdfce9ceSjonathan switch (sw->sw_alg) {
505cdfce9ceSjonathan case CRYPTO_MD5_HMAC:
506e2205fa0Stls case CRYPTO_MD5_HMAC_96:
507cdfce9ceSjonathan case CRYPTO_SHA1_HMAC:
508e2205fa0Stls case CRYPTO_SHA1_HMAC_96:
509b4da53f1Sdrochner case CRYPTO_SHA2_256_HMAC:
510b4da53f1Sdrochner case CRYPTO_SHA2_384_HMAC:
511b4da53f1Sdrochner case CRYPTO_SHA2_512_HMAC:
512cdfce9ceSjonathan case CRYPTO_RIPEMD160_HMAC:
513e2205fa0Stls case CRYPTO_RIPEMD160_HMAC_96:
514cdfce9ceSjonathan if (sw->sw_octx == NULL)
515cdfce9ceSjonathan return EINVAL;
516cdfce9ceSjonathan
517cdfce9ceSjonathan axf->Final(aalg, &ctx);
5189f36e765Sdrochner memcpy(&ctx, sw->sw_octx, axf->ctxsize);
5197bc6d90cSthorpej axf->Update(&ctx, aalg, axf->auth_hash->hashsize);
520cdfce9ceSjonathan axf->Final(aalg, &ctx);
521cdfce9ceSjonathan break;
522cdfce9ceSjonathan
523cdfce9ceSjonathan case CRYPTO_MD5_KPDK:
524cdfce9ceSjonathan case CRYPTO_SHA1_KPDK:
525cdfce9ceSjonathan if (sw->sw_octx == NULL)
526cdfce9ceSjonathan return EINVAL;
527cdfce9ceSjonathan
528cdfce9ceSjonathan axf->Update(&ctx, sw->sw_octx, sw->sw_klen);
529cdfce9ceSjonathan axf->Final(aalg, &ctx);
530cdfce9ceSjonathan break;
531cdfce9ceSjonathan
532cdfce9ceSjonathan case CRYPTO_NULL_HMAC:
533cdfce9ceSjonathan case CRYPTO_MD5:
534cdfce9ceSjonathan case CRYPTO_SHA1:
535ebc232a5Sdrochner case CRYPTO_AES_XCBC_MAC_96:
536cdfce9ceSjonathan axf->Final(aalg, &ctx);
537cdfce9ceSjonathan break;
538cdfce9ceSjonathan }
539cdfce9ceSjonathan
540cdfce9ceSjonathan /* Inject the authentication data */
541de6bc09eSjonathan switch (outtype) {
542de6bc09eSjonathan case CRYPTO_BUF_CONTIG:
54353524e44Schristos (void)memcpy((char *)buf + crd->crd_inject, aalg,
54453524e44Schristos axf->auth_hash->authsize);
545de6bc09eSjonathan break;
546de6bc09eSjonathan case CRYPTO_BUF_MBUF:
547cdfce9ceSjonathan m_copyback((struct mbuf *) buf, crd->crd_inject,
5487bc6d90cSthorpej axf->auth_hash->authsize, aalg);
549de6bc09eSjonathan break;
550de6bc09eSjonathan case CRYPTO_BUF_IOV:
551e2cb8590Scegger memcpy(crp->crp_mac, aalg, axf->auth_hash->authsize);
552de6bc09eSjonathan break;
553de6bc09eSjonathan default:
554de6bc09eSjonathan return EINVAL;
555de6bc09eSjonathan }
556cdfce9ceSjonathan return 0;
557cdfce9ceSjonathan }
558cdfce9ceSjonathan
559cdfce9ceSjonathan /*
5600a8dabdaSdrochner * Apply a combined encryption-authentication transformation
5610a8dabdaSdrochner */
5620a8dabdaSdrochner static int
swcr_combined(struct cryptop * crp,int outtype)5630a8dabdaSdrochner swcr_combined(struct cryptop *crp, int outtype)
5640a8dabdaSdrochner {
5650a8dabdaSdrochner uint32_t blkbuf[howmany(EALG_MAX_BLOCK_LEN, sizeof(uint32_t))];
5660a8dabdaSdrochner u_char *blk = (u_char *)blkbuf;
5670a8dabdaSdrochner u_char aalg[AALG_MAX_RESULT_LEN];
5680a8dabdaSdrochner u_char iv[EALG_MAX_BLOCK_LEN];
5690a8dabdaSdrochner union authctx ctx;
5700a8dabdaSdrochner struct cryptodesc *crd, *crda = NULL, *crde = NULL;
5710a8dabdaSdrochner struct swcr_data *sw, *swa, *swe = NULL;
5720a8dabdaSdrochner const struct swcr_auth_hash *axf = NULL;
5730a8dabdaSdrochner const struct swcr_enc_xform *exf = NULL;
5740a8dabdaSdrochner void *buf = (void *)crp->crp_buf;
5750a8dabdaSdrochner uint32_t *blkp;
5760a8dabdaSdrochner int i, blksz = 0, ivlen = 0, len;
5770a8dabdaSdrochner
5780a8dabdaSdrochner for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
5790a8dabdaSdrochner for (sw = swcr_sessions[crp->crp_sid & 0xffffffff];
5800a8dabdaSdrochner sw && sw->sw_alg != crd->crd_alg;
5810a8dabdaSdrochner sw = sw->sw_next)
5820a8dabdaSdrochner ;
5830a8dabdaSdrochner if (sw == NULL)
5840a8dabdaSdrochner return (EINVAL);
5850a8dabdaSdrochner
5860a8dabdaSdrochner switch (sw->sw_alg) {
5870a8dabdaSdrochner case CRYPTO_AES_GCM_16:
5880a8dabdaSdrochner case CRYPTO_AES_GMAC:
5890a8dabdaSdrochner swe = sw;
5900a8dabdaSdrochner crde = crd;
5910a8dabdaSdrochner exf = swe->sw_exf;
5920a8dabdaSdrochner ivlen = exf->enc_xform->ivsize;
5930a8dabdaSdrochner break;
5940a8dabdaSdrochner case CRYPTO_AES_128_GMAC:
5950a8dabdaSdrochner case CRYPTO_AES_192_GMAC:
5960a8dabdaSdrochner case CRYPTO_AES_256_GMAC:
5970a8dabdaSdrochner swa = sw;
5980a8dabdaSdrochner crda = crd;
5990a8dabdaSdrochner axf = swa->sw_axf;
6000a8dabdaSdrochner if (swa->sw_ictx == 0)
6010a8dabdaSdrochner return (EINVAL);
6020a8dabdaSdrochner memcpy(&ctx, swa->sw_ictx, axf->ctxsize);
6030a8dabdaSdrochner blksz = axf->auth_hash->blocksize;
6040a8dabdaSdrochner break;
6050a8dabdaSdrochner default:
6060a8dabdaSdrochner return (EINVAL);
6070a8dabdaSdrochner }
6080a8dabdaSdrochner }
6090a8dabdaSdrochner if (crde == NULL || crda == NULL)
6100a8dabdaSdrochner return (EINVAL);
6110a8dabdaSdrochner if (outtype == CRYPTO_BUF_CONTIG)
6120a8dabdaSdrochner return (EINVAL);
6130a8dabdaSdrochner
6140a8dabdaSdrochner /* Initialize the IV */
6150a8dabdaSdrochner if (crde->crd_flags & CRD_F_ENCRYPT) {
6160a8dabdaSdrochner /* IV explicitly provided ? */
6170a8dabdaSdrochner if (crde->crd_flags & CRD_F_IV_EXPLICIT) {
6180a8dabdaSdrochner memcpy(iv, crde->crd_iv, ivlen);
6190a8dabdaSdrochner if (exf->reinit)
6200a8dabdaSdrochner exf->reinit(swe->sw_kschedule, iv, 0);
6210a8dabdaSdrochner } else if (exf->reinit)
6220a8dabdaSdrochner exf->reinit(swe->sw_kschedule, 0, iv);
6230a8dabdaSdrochner else
624f27d6532Stls cprng_fast(iv, ivlen);
6250a8dabdaSdrochner
6260a8dabdaSdrochner /* Do we need to write the IV */
6270a8dabdaSdrochner if (!(crde->crd_flags & CRD_F_IV_PRESENT))
6280a8dabdaSdrochner COPYBACK(outtype, buf, crde->crd_inject, ivlen, iv);
6290a8dabdaSdrochner
6300a8dabdaSdrochner } else { /* Decryption */
6310a8dabdaSdrochner /* IV explicitly provided ? */
6320a8dabdaSdrochner if (crde->crd_flags & CRD_F_IV_EXPLICIT)
6330a8dabdaSdrochner memcpy(iv, crde->crd_iv, ivlen);
6340a8dabdaSdrochner else {
6350a8dabdaSdrochner /* Get IV off buf */
6360a8dabdaSdrochner COPYDATA(outtype, buf, crde->crd_inject, ivlen, iv);
6370a8dabdaSdrochner }
6380a8dabdaSdrochner if (exf->reinit)
6390a8dabdaSdrochner exf->reinit(swe->sw_kschedule, iv, 0);
6400a8dabdaSdrochner }
6410a8dabdaSdrochner
6420a8dabdaSdrochner /* Supply MAC with IV */
6430a8dabdaSdrochner if (axf->Reinit)
6440a8dabdaSdrochner axf->Reinit(&ctx, iv, ivlen);
6450a8dabdaSdrochner
6460a8dabdaSdrochner /* Supply MAC with AAD */
6470a8dabdaSdrochner for (i = 0; i < crda->crd_len; i += blksz) {
6480a8dabdaSdrochner len = MIN(crda->crd_len - i, blksz);
6490a8dabdaSdrochner COPYDATA(outtype, buf, crda->crd_skip + i, len, blk);
6500a8dabdaSdrochner axf->Update(&ctx, blk, len);
6510a8dabdaSdrochner }
6520a8dabdaSdrochner
6530a8dabdaSdrochner /* Do encryption/decryption with MAC */
6540a8dabdaSdrochner for (i = 0; i < crde->crd_len; i += blksz) {
6550a8dabdaSdrochner len = MIN(crde->crd_len - i, blksz);
6560a8dabdaSdrochner if (len < blksz)
6570a8dabdaSdrochner memset(blk, 0, blksz);
6580a8dabdaSdrochner COPYDATA(outtype, buf, crde->crd_skip + i, len, blk);
6590a8dabdaSdrochner if (crde->crd_flags & CRD_F_ENCRYPT) {
6600a8dabdaSdrochner exf->encrypt(swe->sw_kschedule, blk);
6610a8dabdaSdrochner axf->Update(&ctx, blk, len);
6620a8dabdaSdrochner } else {
6630a8dabdaSdrochner axf->Update(&ctx, blk, len);
6640a8dabdaSdrochner exf->decrypt(swe->sw_kschedule, blk);
6650a8dabdaSdrochner }
6660a8dabdaSdrochner COPYBACK(outtype, buf, crde->crd_skip + i, len, blk);
6670a8dabdaSdrochner }
6680a8dabdaSdrochner
6690a8dabdaSdrochner /* Do any required special finalization */
6700a8dabdaSdrochner switch (crda->crd_alg) {
6710a8dabdaSdrochner case CRYPTO_AES_128_GMAC:
6720a8dabdaSdrochner case CRYPTO_AES_192_GMAC:
6730a8dabdaSdrochner case CRYPTO_AES_256_GMAC:
6740a8dabdaSdrochner /* length block */
6750a8dabdaSdrochner memset(blk, 0, blksz);
6760a8dabdaSdrochner blkp = (uint32_t *)blk + 1;
6770a8dabdaSdrochner *blkp = htobe32(crda->crd_len * 8);
6780a8dabdaSdrochner blkp = (uint32_t *)blk + 3;
6790a8dabdaSdrochner *blkp = htobe32(crde->crd_len * 8);
6800a8dabdaSdrochner axf->Update(&ctx, blk, blksz);
6810a8dabdaSdrochner break;
6820a8dabdaSdrochner }
6830a8dabdaSdrochner
6840a8dabdaSdrochner /* Finalize MAC */
6850a8dabdaSdrochner axf->Final(aalg, &ctx);
6860a8dabdaSdrochner
6870a8dabdaSdrochner /* Inject the authentication data */
6880a8dabdaSdrochner if (outtype == CRYPTO_BUF_MBUF)
6890a8dabdaSdrochner COPYBACK(outtype, buf, crda->crd_inject, axf->auth_hash->authsize, aalg);
6900a8dabdaSdrochner else
6910a8dabdaSdrochner memcpy(crp->crp_mac, aalg, axf->auth_hash->authsize);
6920a8dabdaSdrochner
6930a8dabdaSdrochner return (0);
6940a8dabdaSdrochner }
6950a8dabdaSdrochner
6960a8dabdaSdrochner /*
697cdfce9ceSjonathan * Apply a compression/decompression algorithm
698cdfce9ceSjonathan */
699cdfce9ceSjonathan static int
swcr_compdec(struct cryptodesc * crd,const struct swcr_data * sw,void * buf,int outtype,int * res_size)7002e4e5505Sdrochner swcr_compdec(struct cryptodesc *crd, const struct swcr_data *sw,
7012e4e5505Sdrochner void *buf, int outtype, int *res_size)
702cdfce9ceSjonathan {
703cdfce9ceSjonathan u_int8_t *data, *out;
7047bc6d90cSthorpej const struct swcr_comp_algo *cxf;
705cdfce9ceSjonathan int adj;
706cdfce9ceSjonathan u_int32_t result;
707cdfce9ceSjonathan
708cdfce9ceSjonathan cxf = sw->sw_cxf;
709cdfce9ceSjonathan
710cdfce9ceSjonathan /* We must handle the whole buffer of data in one time
711cdfce9ceSjonathan * then if there is not all the data in the mbuf, we must
712cdfce9ceSjonathan * copy in a buffer.
713cdfce9ceSjonathan */
714cdfce9ceSjonathan
7155b59f58dSknakahara data = malloc(crd->crd_len, M_CRYPTO_DATA, M_NOWAIT);
716cdfce9ceSjonathan if (data == NULL)
717cdfce9ceSjonathan return (EINVAL);
718cdfce9ceSjonathan COPYDATA(outtype, buf, crd->crd_skip, crd->crd_len, data);
719cdfce9ceSjonathan
720cdfce9ceSjonathan if (crd->crd_flags & CRD_F_COMP)
721cdfce9ceSjonathan result = cxf->compress(data, crd->crd_len, &out);
722cdfce9ceSjonathan else
7231caa9a52Sdrochner result = cxf->decompress(data, crd->crd_len, &out,
7241caa9a52Sdrochner *res_size);
725cdfce9ceSjonathan
7265b59f58dSknakahara free(data, M_CRYPTO_DATA);
727cdfce9ceSjonathan if (result == 0)
728cdfce9ceSjonathan return EINVAL;
729cdfce9ceSjonathan
730cdfce9ceSjonathan /* Copy back the (de)compressed data. m_copyback is
731cdfce9ceSjonathan * extending the mbuf as necessary.
732cdfce9ceSjonathan */
7332e4e5505Sdrochner *res_size = (int)result;
734cdfce9ceSjonathan /* Check the compressed size when doing compression */
7351caa9a52Sdrochner if (crd->crd_flags & CRD_F_COMP &&
7361caa9a52Sdrochner sw->sw_alg == CRYPTO_DEFLATE_COMP_NOGROW &&
7371caa9a52Sdrochner result >= crd->crd_len) {
738cdfce9ceSjonathan /* Compression was useless, we lost time */
7399b87d582Scegger free(out, M_CRYPTO_DATA);
740cdfce9ceSjonathan return 0;
741cdfce9ceSjonathan }
742cdfce9ceSjonathan
743cdfce9ceSjonathan COPYBACK(outtype, buf, crd->crd_skip, result, out);
744cdfce9ceSjonathan if (result < crd->crd_len) {
745cdfce9ceSjonathan adj = result - crd->crd_len;
746cdfce9ceSjonathan if (outtype == CRYPTO_BUF_MBUF) {
747cdfce9ceSjonathan m_adj((struct mbuf *)buf, adj);
748cdfce9ceSjonathan }
74936ea3668Sdarran /* Don't adjust the iov_len, it breaks the kmem_free */
750cdfce9ceSjonathan }
7519b87d582Scegger free(out, M_CRYPTO_DATA);
752cdfce9ceSjonathan return 0;
753cdfce9ceSjonathan }
754cdfce9ceSjonathan
755cdfce9ceSjonathan /*
756cdfce9ceSjonathan * Generate a new software session.
757cdfce9ceSjonathan */
758cdfce9ceSjonathan static int
swcr_newsession(void * arg,u_int32_t * sid,struct cryptoini * cri)759168cd830Schristos swcr_newsession(void *arg, u_int32_t *sid, struct cryptoini *cri)
760cdfce9ceSjonathan {
761cdfce9ceSjonathan struct swcr_data **swd;
762cfd5cbf4Sknakahara struct swcr_data *first, *tmp;
7637bc6d90cSthorpej const struct swcr_auth_hash *axf;
7647bc6d90cSthorpej const struct swcr_enc_xform *txf;
7657bc6d90cSthorpej const struct swcr_comp_algo *cxf;
766cdfce9ceSjonathan u_int32_t i;
767cdfce9ceSjonathan int k, error;
768cdfce9ceSjonathan
769cdfce9ceSjonathan if (swcr_sessions) {
770cdfce9ceSjonathan for (i = 1; i < swcr_sesnum; i++)
771cdfce9ceSjonathan if (swcr_sessions[i] == NULL)
772cdfce9ceSjonathan break;
773cdfce9ceSjonathan } else
774cdfce9ceSjonathan i = 1; /* NB: to silence compiler warning */
775cdfce9ceSjonathan
776cdfce9ceSjonathan if (swcr_sessions == NULL || i == swcr_sesnum) {
77759a04e4aSknakahara u_int32_t newnum;
77859a04e4aSknakahara struct swcr_data **newsessions;
77959a04e4aSknakahara
780cdfce9ceSjonathan if (swcr_sessions == NULL) {
781cdfce9ceSjonathan i = 1; /* We leave swcr_sessions[0] empty */
78259a04e4aSknakahara newnum = CRYPTO_SW_SESSIONS;
783cdfce9ceSjonathan } else
78459a04e4aSknakahara newnum = swcr_sesnum *= 2;
785cdfce9ceSjonathan
78659a04e4aSknakahara newsessions = kmem_zalloc(newnum * sizeof(struct swcr_data *),
7873ca2c3f4Sknakahara KM_NOSLEEP);
78859a04e4aSknakahara if (newsessions == NULL) {
789cdfce9ceSjonathan return ENOBUFS;
790cdfce9ceSjonathan }
791cdfce9ceSjonathan
792cdfce9ceSjonathan /* Copy existing sessions */
793cdfce9ceSjonathan if (swcr_sessions) {
79459a04e4aSknakahara memcpy(newsessions, swcr_sessions,
79559a04e4aSknakahara swcr_sesnum * sizeof(struct swcr_data *));
7963ca2c3f4Sknakahara kmem_free(swcr_sessions,
79759a04e4aSknakahara swcr_sesnum * sizeof(struct swcr_data *));
798cdfce9ceSjonathan }
799cdfce9ceSjonathan
80059a04e4aSknakahara swcr_sesnum = newnum;
80159a04e4aSknakahara swcr_sessions = newsessions;
802cdfce9ceSjonathan }
803cdfce9ceSjonathan
804cfd5cbf4Sknakahara first = NULL;
805cfd5cbf4Sknakahara swd = &tmp;
806cdfce9ceSjonathan while (cri) {
8073ca2c3f4Sknakahara *swd = kmem_zalloc(sizeof **swd, KM_NOSLEEP);
808cdfce9ceSjonathan if (*swd == NULL) {
809cfd5cbf4Sknakahara if (first != NULL)
810cfd5cbf4Sknakahara swcr_freesession_internal(first);
811cdfce9ceSjonathan return ENOBUFS;
812cfd5cbf4Sknakahara } else if (first == NULL)
813cfd5cbf4Sknakahara first = *swd;
814cdfce9ceSjonathan
815cdfce9ceSjonathan switch (cri->cri_alg) {
816cdfce9ceSjonathan case CRYPTO_DES_CBC:
8177bc6d90cSthorpej txf = &swcr_enc_xform_des;
818cdfce9ceSjonathan goto enccommon;
819cdfce9ceSjonathan case CRYPTO_3DES_CBC:
8207bc6d90cSthorpej txf = &swcr_enc_xform_3des;
821cdfce9ceSjonathan goto enccommon;
822cdfce9ceSjonathan case CRYPTO_BLF_CBC:
8237bc6d90cSthorpej txf = &swcr_enc_xform_blf;
824cdfce9ceSjonathan goto enccommon;
825cdfce9ceSjonathan case CRYPTO_CAST_CBC:
8267bc6d90cSthorpej txf = &swcr_enc_xform_cast5;
827cdfce9ceSjonathan goto enccommon;
828cdfce9ceSjonathan case CRYPTO_SKIPJACK_CBC:
8297bc6d90cSthorpej txf = &swcr_enc_xform_skipjack;
830cdfce9ceSjonathan goto enccommon;
8318835ffd0Sriastradh case CRYPTO_AES_CBC:
8328835ffd0Sriastradh txf = &swcr_enc_xform_aes;
833cdfce9ceSjonathan goto enccommon;
8343d2cef17Sdrochner case CRYPTO_CAMELLIA_CBC:
8353d2cef17Sdrochner txf = &swcr_enc_xform_camellia;
8363d2cef17Sdrochner goto enccommon;
8373e66cf48Sdrochner case CRYPTO_AES_CTR:
8383e66cf48Sdrochner txf = &swcr_enc_xform_aes_ctr;
8393e66cf48Sdrochner goto enccommon;
8400a8dabdaSdrochner case CRYPTO_AES_GCM_16:
8410a8dabdaSdrochner txf = &swcr_enc_xform_aes_gcm;
8420a8dabdaSdrochner goto enccommon;
84349c12b7aSdrochner case CRYPTO_AES_GMAC:
84449c12b7aSdrochner txf = &swcr_enc_xform_aes_gmac;
84549c12b7aSdrochner goto enccommon;
846cdfce9ceSjonathan case CRYPTO_NULL_CBC:
8477bc6d90cSthorpej txf = &swcr_enc_xform_null;
848cdfce9ceSjonathan goto enccommon;
849cdfce9ceSjonathan enccommon:
850cdfce9ceSjonathan error = txf->setkey(&((*swd)->sw_kschedule),
851cdfce9ceSjonathan cri->cri_key, cri->cri_klen / 8);
852cdfce9ceSjonathan if (error) {
853cfd5cbf4Sknakahara swcr_freesession_internal(first);
854cdfce9ceSjonathan return error;
855cdfce9ceSjonathan }
856cdfce9ceSjonathan (*swd)->sw_exf = txf;
857cdfce9ceSjonathan break;
858cdfce9ceSjonathan
859cdfce9ceSjonathan case CRYPTO_MD5_HMAC:
860e2205fa0Stls axf = &swcr_auth_hash_hmac_md5;
861e2205fa0Stls goto authcommon;
862e2205fa0Stls case CRYPTO_MD5_HMAC_96:
8637bc6d90cSthorpej axf = &swcr_auth_hash_hmac_md5_96;
864cdfce9ceSjonathan goto authcommon;
865cdfce9ceSjonathan case CRYPTO_SHA1_HMAC:
866e2205fa0Stls axf = &swcr_auth_hash_hmac_sha1;
867e2205fa0Stls goto authcommon;
868e2205fa0Stls case CRYPTO_SHA1_HMAC_96:
8697bc6d90cSthorpej axf = &swcr_auth_hash_hmac_sha1_96;
870cdfce9ceSjonathan goto authcommon;
871b4da53f1Sdrochner case CRYPTO_SHA2_256_HMAC:
8727bc6d90cSthorpej axf = &swcr_auth_hash_hmac_sha2_256;
873b4da53f1Sdrochner goto authcommon;
874b4da53f1Sdrochner case CRYPTO_SHA2_384_HMAC:
8757bc6d90cSthorpej axf = &swcr_auth_hash_hmac_sha2_384;
876b4da53f1Sdrochner goto authcommon;
877b4da53f1Sdrochner case CRYPTO_SHA2_512_HMAC:
8787bc6d90cSthorpej axf = &swcr_auth_hash_hmac_sha2_512;
879cdfce9ceSjonathan goto authcommon;
880cdfce9ceSjonathan case CRYPTO_NULL_HMAC:
8817bc6d90cSthorpej axf = &swcr_auth_hash_null;
882cdfce9ceSjonathan goto authcommon;
883cdfce9ceSjonathan case CRYPTO_RIPEMD160_HMAC:
884e2205fa0Stls axf = &swcr_auth_hash_hmac_ripemd_160;
885e2205fa0Stls goto authcommon;
886e2205fa0Stls case CRYPTO_RIPEMD160_HMAC_96:
8877bc6d90cSthorpej axf = &swcr_auth_hash_hmac_ripemd_160_96;
888e2205fa0Stls goto authcommon; /* leave this for safety */
889cdfce9ceSjonathan authcommon:
8908835ffd0Sriastradh (*swd)->sw_ictx = kmem_alloc(axf->ctxsize, KM_NOSLEEP);
891cdfce9ceSjonathan if ((*swd)->sw_ictx == NULL) {
892cfd5cbf4Sknakahara swcr_freesession_internal(first);
893cdfce9ceSjonathan return ENOBUFS;
894cdfce9ceSjonathan }
895cdfce9ceSjonathan
8968835ffd0Sriastradh (*swd)->sw_octx = kmem_alloc(axf->ctxsize, KM_NOSLEEP);
897cdfce9ceSjonathan if ((*swd)->sw_octx == NULL) {
898cfd5cbf4Sknakahara swcr_freesession_internal(first);
899cdfce9ceSjonathan return ENOBUFS;
900cdfce9ceSjonathan }
901cdfce9ceSjonathan
902cdfce9ceSjonathan for (k = 0; k < cri->cri_klen / 8; k++)
903cdfce9ceSjonathan cri->cri_key[k] ^= HMAC_IPAD_VAL;
904cdfce9ceSjonathan
905cdfce9ceSjonathan axf->Init((*swd)->sw_ictx);
906cdfce9ceSjonathan axf->Update((*swd)->sw_ictx, cri->cri_key,
907cdfce9ceSjonathan cri->cri_klen / 8);
908cdfce9ceSjonathan axf->Update((*swd)->sw_ictx, hmac_ipad_buffer,
909b4da53f1Sdrochner axf->auth_hash->blocksize - (cri->cri_klen / 8));
910cdfce9ceSjonathan
911cdfce9ceSjonathan for (k = 0; k < cri->cri_klen / 8; k++)
912cdfce9ceSjonathan cri->cri_key[k] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
913cdfce9ceSjonathan
914cdfce9ceSjonathan axf->Init((*swd)->sw_octx);
915cdfce9ceSjonathan axf->Update((*swd)->sw_octx, cri->cri_key,
916cdfce9ceSjonathan cri->cri_klen / 8);
917cdfce9ceSjonathan axf->Update((*swd)->sw_octx, hmac_opad_buffer,
918b4da53f1Sdrochner axf->auth_hash->blocksize - (cri->cri_klen / 8));
919cdfce9ceSjonathan
920cdfce9ceSjonathan for (k = 0; k < cri->cri_klen / 8; k++)
921cdfce9ceSjonathan cri->cri_key[k] ^= HMAC_OPAD_VAL;
922cdfce9ceSjonathan (*swd)->sw_axf = axf;
923cdfce9ceSjonathan break;
924cdfce9ceSjonathan
925cdfce9ceSjonathan case CRYPTO_MD5_KPDK:
9267bc6d90cSthorpej axf = &swcr_auth_hash_key_md5;
927cdfce9ceSjonathan goto auth2common;
928cdfce9ceSjonathan
9297654585cSozaki-r case CRYPTO_SHA1_KPDK: {
9307654585cSozaki-r unsigned char digest[SHA1_DIGEST_LENGTH];
9317654585cSozaki-r CTASSERT(SHA1_DIGEST_LENGTH >= MD5_DIGEST_LENGTH);
9327bc6d90cSthorpej axf = &swcr_auth_hash_key_sha1;
933cdfce9ceSjonathan auth2common:
9348835ffd0Sriastradh (*swd)->sw_ictx = kmem_alloc(axf->ctxsize, KM_NOSLEEP);
935cdfce9ceSjonathan if ((*swd)->sw_ictx == NULL) {
936cfd5cbf4Sknakahara swcr_freesession_internal(first);
937cdfce9ceSjonathan return ENOBUFS;
938cdfce9ceSjonathan }
939cdfce9ceSjonathan
940cdfce9ceSjonathan /* Store the key so we can "append" it to the payload */
9418835ffd0Sriastradh (*swd)->sw_octx = kmem_alloc(cri->cri_klen / 8,
9428835ffd0Sriastradh KM_NOSLEEP);
943cdfce9ceSjonathan if ((*swd)->sw_octx == NULL) {
944cfd5cbf4Sknakahara swcr_freesession_internal(first);
945cdfce9ceSjonathan return ENOBUFS;
946cdfce9ceSjonathan }
947cdfce9ceSjonathan
948cdfce9ceSjonathan (*swd)->sw_klen = cri->cri_klen / 8;
949e2cb8590Scegger memcpy((*swd)->sw_octx, cri->cri_key, cri->cri_klen / 8);
950cdfce9ceSjonathan axf->Init((*swd)->sw_ictx);
951cdfce9ceSjonathan axf->Update((*swd)->sw_ictx, cri->cri_key,
952cdfce9ceSjonathan cri->cri_klen / 8);
9537654585cSozaki-r axf->Final(digest, (*swd)->sw_ictx);
954cdfce9ceSjonathan (*swd)->sw_axf = axf;
955cdfce9ceSjonathan break;
9567654585cSozaki-r }
957cdfce9ceSjonathan
958cdfce9ceSjonathan case CRYPTO_MD5:
9597bc6d90cSthorpej axf = &swcr_auth_hash_md5;
960cdfce9ceSjonathan goto auth3common;
961cdfce9ceSjonathan
962cdfce9ceSjonathan case CRYPTO_SHA1:
9637bc6d90cSthorpej axf = &swcr_auth_hash_sha1;
964cdfce9ceSjonathan auth3common:
9658835ffd0Sriastradh (*swd)->sw_ictx = kmem_alloc(axf->ctxsize, KM_NOSLEEP);
966cdfce9ceSjonathan if ((*swd)->sw_ictx == NULL) {
967cfd5cbf4Sknakahara swcr_freesession_internal(first);
968cdfce9ceSjonathan return ENOBUFS;
969cdfce9ceSjonathan }
970cdfce9ceSjonathan
971cdfce9ceSjonathan axf->Init((*swd)->sw_ictx);
972cdfce9ceSjonathan (*swd)->sw_axf = axf;
973cdfce9ceSjonathan break;
974cdfce9ceSjonathan
975ebc232a5Sdrochner case CRYPTO_AES_XCBC_MAC_96:
976ebc232a5Sdrochner axf = &swcr_auth_hash_aes_xcbc_mac;
9770a8dabdaSdrochner goto auth4common;
9780a8dabdaSdrochner case CRYPTO_AES_128_GMAC:
9790a8dabdaSdrochner axf = &swcr_auth_hash_gmac_aes_128;
9800a8dabdaSdrochner goto auth4common;
9810a8dabdaSdrochner case CRYPTO_AES_192_GMAC:
9820a8dabdaSdrochner axf = &swcr_auth_hash_gmac_aes_192;
9830a8dabdaSdrochner goto auth4common;
9840a8dabdaSdrochner case CRYPTO_AES_256_GMAC:
9850a8dabdaSdrochner axf = &swcr_auth_hash_gmac_aes_256;
9860a8dabdaSdrochner auth4common:
9878835ffd0Sriastradh (*swd)->sw_ictx = kmem_alloc(axf->ctxsize, KM_NOSLEEP);
988ebc232a5Sdrochner if ((*swd)->sw_ictx == NULL) {
989cfd5cbf4Sknakahara swcr_freesession_internal(first);
990ebc232a5Sdrochner return ENOBUFS;
991ebc232a5Sdrochner }
992ebc232a5Sdrochner axf->Init((*swd)->sw_ictx);
993ebc232a5Sdrochner axf->Setkey((*swd)->sw_ictx,
994ebc232a5Sdrochner cri->cri_key, cri->cri_klen / 8);
995ebc232a5Sdrochner (*swd)->sw_axf = axf;
996ebc232a5Sdrochner break;
997ebc232a5Sdrochner
998cdfce9ceSjonathan case CRYPTO_DEFLATE_COMP:
9997bc6d90cSthorpej cxf = &swcr_comp_algo_deflate;
1000cdfce9ceSjonathan (*swd)->sw_cxf = cxf;
1001cdfce9ceSjonathan break;
100236ea3668Sdarran
10031caa9a52Sdrochner case CRYPTO_DEFLATE_COMP_NOGROW:
10041caa9a52Sdrochner cxf = &swcr_comp_algo_deflate_nogrow;
10051caa9a52Sdrochner (*swd)->sw_cxf = cxf;
10061caa9a52Sdrochner break;
10071caa9a52Sdrochner
100836ea3668Sdarran case CRYPTO_GZIP_COMP:
100936ea3668Sdarran cxf = &swcr_comp_algo_gzip;
101036ea3668Sdarran (*swd)->sw_cxf = cxf;
101136ea3668Sdarran break;
1012cdfce9ceSjonathan default:
1013cfd5cbf4Sknakahara swcr_freesession_internal(first);
1014cdfce9ceSjonathan return EINVAL;
1015cdfce9ceSjonathan }
1016cdfce9ceSjonathan
1017cdfce9ceSjonathan (*swd)->sw_alg = cri->cri_alg;
1018cdfce9ceSjonathan cri = cri->cri_next;
1019cdfce9ceSjonathan swd = &((*swd)->sw_next);
1020cdfce9ceSjonathan }
1021cfd5cbf4Sknakahara
1022cfd5cbf4Sknakahara swcr_sessions[i] = first;
1023cfd5cbf4Sknakahara *sid = i;
1024cdfce9ceSjonathan return 0;
1025cdfce9ceSjonathan }
1026cdfce9ceSjonathan
1027cfd5cbf4Sknakahara static void
swcr_freesession_internal(struct swcr_data * arg)1028cfd5cbf4Sknakahara swcr_freesession_internal(struct swcr_data *arg)
1029cdfce9ceSjonathan {
1030cfd5cbf4Sknakahara struct swcr_data *swd, *swd0;
10317bc6d90cSthorpej const struct swcr_enc_xform *txf;
10327bc6d90cSthorpej const struct swcr_auth_hash *axf;
1033cdfce9ceSjonathan
1034cfd5cbf4Sknakahara if (arg == NULL)
1035cfd5cbf4Sknakahara return;
1036cdfce9ceSjonathan
1037cfd5cbf4Sknakahara swd0 = arg;
1038cfd5cbf4Sknakahara while ((swd = swd0) != NULL) {
1039cfd5cbf4Sknakahara swd0 = swd->sw_next;
1040cdfce9ceSjonathan
1041cdfce9ceSjonathan switch (swd->sw_alg) {
1042cdfce9ceSjonathan case CRYPTO_DES_CBC:
1043cdfce9ceSjonathan case CRYPTO_3DES_CBC:
1044cdfce9ceSjonathan case CRYPTO_BLF_CBC:
1045cdfce9ceSjonathan case CRYPTO_CAST_CBC:
1046cdfce9ceSjonathan case CRYPTO_SKIPJACK_CBC:
10478835ffd0Sriastradh case CRYPTO_AES_CBC:
10483d2cef17Sdrochner case CRYPTO_CAMELLIA_CBC:
10493e66cf48Sdrochner case CRYPTO_AES_CTR:
10500a8dabdaSdrochner case CRYPTO_AES_GCM_16:
105149c12b7aSdrochner case CRYPTO_AES_GMAC:
1052cdfce9ceSjonathan case CRYPTO_NULL_CBC:
1053cdfce9ceSjonathan txf = swd->sw_exf;
1054cdfce9ceSjonathan
1055cdfce9ceSjonathan if (swd->sw_kschedule)
1056cdfce9ceSjonathan txf->zerokey(&(swd->sw_kschedule));
1057cdfce9ceSjonathan break;
1058cdfce9ceSjonathan
1059cdfce9ceSjonathan case CRYPTO_MD5_HMAC:
1060e2205fa0Stls case CRYPTO_MD5_HMAC_96:
1061cdfce9ceSjonathan case CRYPTO_SHA1_HMAC:
1062e2205fa0Stls case CRYPTO_SHA1_HMAC_96:
1063b4da53f1Sdrochner case CRYPTO_SHA2_256_HMAC:
1064b4da53f1Sdrochner case CRYPTO_SHA2_384_HMAC:
1065b4da53f1Sdrochner case CRYPTO_SHA2_512_HMAC:
1066cdfce9ceSjonathan case CRYPTO_RIPEMD160_HMAC:
1067e2205fa0Stls case CRYPTO_RIPEMD160_HMAC_96:
1068cdfce9ceSjonathan case CRYPTO_NULL_HMAC:
1069cdfce9ceSjonathan axf = swd->sw_axf;
1070cdfce9ceSjonathan
1071cdfce9ceSjonathan if (swd->sw_ictx) {
107282db4b98Sriastradh explicit_memset(swd->sw_ictx, 0, axf->ctxsize);
10738835ffd0Sriastradh kmem_free(swd->sw_ictx, axf->ctxsize);
1074cdfce9ceSjonathan }
1075cdfce9ceSjonathan if (swd->sw_octx) {
107682db4b98Sriastradh explicit_memset(swd->sw_octx, 0, axf->ctxsize);
10778835ffd0Sriastradh kmem_free(swd->sw_octx, axf->ctxsize);
1078cdfce9ceSjonathan }
1079cdfce9ceSjonathan break;
1080cdfce9ceSjonathan
1081cdfce9ceSjonathan case CRYPTO_MD5_KPDK:
1082cdfce9ceSjonathan case CRYPTO_SHA1_KPDK:
1083cdfce9ceSjonathan axf = swd->sw_axf;
1084cdfce9ceSjonathan
1085cdfce9ceSjonathan if (swd->sw_ictx) {
108682db4b98Sriastradh explicit_memset(swd->sw_ictx, 0, axf->ctxsize);
10878835ffd0Sriastradh kmem_free(swd->sw_ictx, axf->ctxsize);
1088cdfce9ceSjonathan }
1089cdfce9ceSjonathan if (swd->sw_octx) {
109082db4b98Sriastradh explicit_memset(swd->sw_octx, 0, swd->sw_klen);
10915da7826cSriastradh kmem_free(swd->sw_octx, swd->sw_klen);
1092cdfce9ceSjonathan }
1093cdfce9ceSjonathan break;
1094cdfce9ceSjonathan
1095cdfce9ceSjonathan case CRYPTO_MD5:
1096cdfce9ceSjonathan case CRYPTO_SHA1:
1097ebc232a5Sdrochner case CRYPTO_AES_XCBC_MAC_96:
10980a8dabdaSdrochner case CRYPTO_AES_128_GMAC:
10990a8dabdaSdrochner case CRYPTO_AES_192_GMAC:
11000a8dabdaSdrochner case CRYPTO_AES_256_GMAC:
1101cdfce9ceSjonathan axf = swd->sw_axf;
1102cdfce9ceSjonathan
11038588929dSdrochner if (swd->sw_ictx) {
110482db4b98Sriastradh explicit_memset(swd->sw_ictx, 0, axf->ctxsize);
11058835ffd0Sriastradh kmem_free(swd->sw_ictx, axf->ctxsize);
11068588929dSdrochner }
1107cdfce9ceSjonathan break;
1108cdfce9ceSjonathan
1109cdfce9ceSjonathan case CRYPTO_DEFLATE_COMP:
11101caa9a52Sdrochner case CRYPTO_DEFLATE_COMP_NOGROW:
111136ea3668Sdarran case CRYPTO_GZIP_COMP:
1112cdfce9ceSjonathan break;
1113cdfce9ceSjonathan }
1114cdfce9ceSjonathan
11155b59f58dSknakahara kmem_free(swd, sizeof(*swd));
1116cdfce9ceSjonathan }
1117cfd5cbf4Sknakahara }
1118cfd5cbf4Sknakahara
1119cfd5cbf4Sknakahara /*
1120cfd5cbf4Sknakahara * Free a session.
1121cfd5cbf4Sknakahara */
1122*ee55792fSriastradh static void
swcr_freesession(void * arg,u_int64_t tid)1123cfd5cbf4Sknakahara swcr_freesession(void *arg, u_int64_t tid)
1124cfd5cbf4Sknakahara {
1125cfd5cbf4Sknakahara struct swcr_data *swd;
1126cfd5cbf4Sknakahara u_int32_t sid = ((u_int32_t) tid) & 0xffffffff;
1127cfd5cbf4Sknakahara
1128486d5a49Sriastradh KASSERTMSG(sid < swcr_sesnum, "sid=%"PRIu32" swcr_sesnum=%"PRIu32,
1129486d5a49Sriastradh sid, swcr_sesnum);
1130486d5a49Sriastradh KASSERT(swcr_sessions[sid]);
1131cfd5cbf4Sknakahara
1132cfd5cbf4Sknakahara swd = swcr_sessions[sid];
1133cfd5cbf4Sknakahara swcr_sessions[sid] = NULL;
1134cfd5cbf4Sknakahara swcr_freesession_internal(swd);
1135cdfce9ceSjonathan }
1136cdfce9ceSjonathan
1137cdfce9ceSjonathan /*
1138cdfce9ceSjonathan * Process a software request.
1139cdfce9ceSjonathan */
1140cdfce9ceSjonathan static int
swcr_process(void * arg,struct cryptop * crp,int hint)1141168cd830Schristos swcr_process(void *arg, struct cryptop *crp, int hint)
1142cdfce9ceSjonathan {
1143cdfce9ceSjonathan struct cryptodesc *crd;
1144cdfce9ceSjonathan struct swcr_data *sw;
1145cdfce9ceSjonathan u_int32_t lid;
1146cdfce9ceSjonathan int type;
1147cdfce9ceSjonathan
1148cdfce9ceSjonathan /* Sanity check */
1149cdfce9ceSjonathan if (crp == NULL)
1150cdfce9ceSjonathan return EINVAL;
1151cdfce9ceSjonathan
1152cdfce9ceSjonathan if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
1153cdfce9ceSjonathan crp->crp_etype = EINVAL;
1154cdfce9ceSjonathan goto done;
1155cdfce9ceSjonathan }
1156cdfce9ceSjonathan
1157cdfce9ceSjonathan lid = crp->crp_sid & 0xffffffff;
1158cdfce9ceSjonathan if (lid >= swcr_sesnum || lid == 0 || swcr_sessions[lid] == NULL) {
1159cdfce9ceSjonathan crp->crp_etype = ENOENT;
1160cdfce9ceSjonathan goto done;
1161cdfce9ceSjonathan }
1162cdfce9ceSjonathan
1163cdfce9ceSjonathan if (crp->crp_flags & CRYPTO_F_IMBUF) {
1164cdfce9ceSjonathan type = CRYPTO_BUF_MBUF;
1165cdfce9ceSjonathan } else if (crp->crp_flags & CRYPTO_F_IOV) {
1166cdfce9ceSjonathan type = CRYPTO_BUF_IOV;
1167cdfce9ceSjonathan } else {
1168cdfce9ceSjonathan type = CRYPTO_BUF_CONTIG;
1169cdfce9ceSjonathan }
1170cdfce9ceSjonathan
1171cdfce9ceSjonathan /* Go through crypto descriptors, processing as we go */
1172cdfce9ceSjonathan for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
1173cdfce9ceSjonathan /*
1174cdfce9ceSjonathan * Find the crypto context.
1175cdfce9ceSjonathan *
1176cdfce9ceSjonathan * XXX Note that the logic here prevents us from having
1177cdfce9ceSjonathan * XXX the same algorithm multiple times in a session
1178cdfce9ceSjonathan * XXX (or rather, we can but it won't give us the right
1179cdfce9ceSjonathan * XXX results). To do that, we'd need some way of differentiating
1180cdfce9ceSjonathan * XXX between the various instances of an algorithm (so we can
1181cdfce9ceSjonathan * XXX locate the correct crypto context).
1182cdfce9ceSjonathan */
1183cdfce9ceSjonathan for (sw = swcr_sessions[lid];
1184cdfce9ceSjonathan sw && sw->sw_alg != crd->crd_alg;
1185cdfce9ceSjonathan sw = sw->sw_next)
1186cdfce9ceSjonathan ;
1187cdfce9ceSjonathan
1188cdfce9ceSjonathan /* No such context ? */
1189cdfce9ceSjonathan if (sw == NULL) {
1190cdfce9ceSjonathan crp->crp_etype = EINVAL;
1191cdfce9ceSjonathan goto done;
1192cdfce9ceSjonathan }
1193cdfce9ceSjonathan
1194cdfce9ceSjonathan switch (sw->sw_alg) {
1195cdfce9ceSjonathan case CRYPTO_DES_CBC:
1196cdfce9ceSjonathan case CRYPTO_3DES_CBC:
1197cdfce9ceSjonathan case CRYPTO_BLF_CBC:
1198cdfce9ceSjonathan case CRYPTO_CAST_CBC:
1199cdfce9ceSjonathan case CRYPTO_SKIPJACK_CBC:
12008835ffd0Sriastradh case CRYPTO_AES_CBC:
12013d2cef17Sdrochner case CRYPTO_CAMELLIA_CBC:
12023e66cf48Sdrochner case CRYPTO_AES_CTR:
1203cdfce9ceSjonathan if ((crp->crp_etype = swcr_encdec(crd, sw,
1204cdfce9ceSjonathan crp->crp_buf, type)) != 0)
1205cdfce9ceSjonathan goto done;
1206cdfce9ceSjonathan break;
1207cdfce9ceSjonathan case CRYPTO_NULL_CBC:
1208cdfce9ceSjonathan crp->crp_etype = 0;
1209cdfce9ceSjonathan break;
1210cdfce9ceSjonathan case CRYPTO_MD5_HMAC:
1211e2205fa0Stls case CRYPTO_MD5_HMAC_96:
1212cdfce9ceSjonathan case CRYPTO_SHA1_HMAC:
1213e2205fa0Stls case CRYPTO_SHA1_HMAC_96:
1214b4da53f1Sdrochner case CRYPTO_SHA2_256_HMAC:
1215b4da53f1Sdrochner case CRYPTO_SHA2_384_HMAC:
1216b4da53f1Sdrochner case CRYPTO_SHA2_512_HMAC:
1217cdfce9ceSjonathan case CRYPTO_RIPEMD160_HMAC:
1218e2205fa0Stls case CRYPTO_RIPEMD160_HMAC_96:
1219cdfce9ceSjonathan case CRYPTO_NULL_HMAC:
1220cdfce9ceSjonathan case CRYPTO_MD5_KPDK:
1221cdfce9ceSjonathan case CRYPTO_SHA1_KPDK:
1222cdfce9ceSjonathan case CRYPTO_MD5:
1223cdfce9ceSjonathan case CRYPTO_SHA1:
1224ebc232a5Sdrochner case CRYPTO_AES_XCBC_MAC_96:
1225cdfce9ceSjonathan if ((crp->crp_etype = swcr_authcompute(crp, crd, sw,
1226cdfce9ceSjonathan crp->crp_buf, type)) != 0)
1227cdfce9ceSjonathan goto done;
1228cdfce9ceSjonathan break;
1229cdfce9ceSjonathan
12300a8dabdaSdrochner case CRYPTO_AES_GCM_16:
12310a8dabdaSdrochner case CRYPTO_AES_GMAC:
12320a8dabdaSdrochner case CRYPTO_AES_128_GMAC:
12330a8dabdaSdrochner case CRYPTO_AES_192_GMAC:
12340a8dabdaSdrochner case CRYPTO_AES_256_GMAC:
12350a8dabdaSdrochner crp->crp_etype = swcr_combined(crp, type);
12360a8dabdaSdrochner goto done;
12370a8dabdaSdrochner
1238cdfce9ceSjonathan case CRYPTO_DEFLATE_COMP:
12391caa9a52Sdrochner case CRYPTO_DEFLATE_COMP_NOGROW:
124036ea3668Sdarran case CRYPTO_GZIP_COMP:
1241c4e549c7Sknakahara DPRINTF("compdec for %d\n", sw->sw_alg);
1242cdfce9ceSjonathan if ((crp->crp_etype = swcr_compdec(crd, sw,
12432e4e5505Sdrochner crp->crp_buf, type, &crp->crp_olen)) != 0)
1244cdfce9ceSjonathan goto done;
1245cdfce9ceSjonathan break;
1246cdfce9ceSjonathan
1247cdfce9ceSjonathan default:
1248cdfce9ceSjonathan /* Unknown/unsupported algorithm */
1249cdfce9ceSjonathan crp->crp_etype = EINVAL;
1250cdfce9ceSjonathan goto done;
1251cdfce9ceSjonathan }
1252cdfce9ceSjonathan }
1253cdfce9ceSjonathan
1254cdfce9ceSjonathan done:
1255c4e549c7Sknakahara DPRINTF("request %p done\n", crp);
1256cdfce9ceSjonathan crypto_done(crp);
1257cdfce9ceSjonathan return 0;
1258cdfce9ceSjonathan }
1259cdfce9ceSjonathan
12607bc6d90cSthorpej static void
swcr_init(void)1261cdfce9ceSjonathan swcr_init(void)
1262cdfce9ceSjonathan {
1263cdfce9ceSjonathan swcr_id = crypto_get_driverid(CRYPTOCAP_F_SOFTWARE);
1264cdfce9ceSjonathan if (swcr_id < 0) {
1265cdfce9ceSjonathan /* This should never happen */
1266cdfce9ceSjonathan panic("Software crypto device cannot initialize!");
1267cdfce9ceSjonathan }
1268cdfce9ceSjonathan
1269cdfce9ceSjonathan crypto_register(swcr_id, CRYPTO_DES_CBC,
1270cdfce9ceSjonathan 0, 0, swcr_newsession, swcr_freesession, swcr_process, NULL);
1271cdfce9ceSjonathan #define REGISTER(alg) \
1272cdfce9ceSjonathan crypto_register(swcr_id, alg, 0, 0, NULL, NULL, NULL, NULL)
1273cdfce9ceSjonathan
1274cdfce9ceSjonathan REGISTER(CRYPTO_3DES_CBC);
1275cdfce9ceSjonathan REGISTER(CRYPTO_BLF_CBC);
1276cdfce9ceSjonathan REGISTER(CRYPTO_CAST_CBC);
1277cdfce9ceSjonathan REGISTER(CRYPTO_SKIPJACK_CBC);
12783d2cef17Sdrochner REGISTER(CRYPTO_CAMELLIA_CBC);
12793e66cf48Sdrochner REGISTER(CRYPTO_AES_CTR);
12800a8dabdaSdrochner REGISTER(CRYPTO_AES_GCM_16);
12810a8dabdaSdrochner REGISTER(CRYPTO_AES_GMAC);
1282cdfce9ceSjonathan REGISTER(CRYPTO_NULL_CBC);
1283cdfce9ceSjonathan REGISTER(CRYPTO_MD5_HMAC);
1284e2205fa0Stls REGISTER(CRYPTO_MD5_HMAC_96);
1285cdfce9ceSjonathan REGISTER(CRYPTO_SHA1_HMAC);
1286e2205fa0Stls REGISTER(CRYPTO_SHA1_HMAC_96);
1287b4da53f1Sdrochner REGISTER(CRYPTO_SHA2_256_HMAC);
1288b4da53f1Sdrochner REGISTER(CRYPTO_SHA2_384_HMAC);
1289b4da53f1Sdrochner REGISTER(CRYPTO_SHA2_512_HMAC);
1290cdfce9ceSjonathan REGISTER(CRYPTO_RIPEMD160_HMAC);
1291e2205fa0Stls REGISTER(CRYPTO_RIPEMD160_HMAC_96);
1292cdfce9ceSjonathan REGISTER(CRYPTO_NULL_HMAC);
1293cdfce9ceSjonathan REGISTER(CRYPTO_MD5_KPDK);
1294cdfce9ceSjonathan REGISTER(CRYPTO_SHA1_KPDK);
1295cdfce9ceSjonathan REGISTER(CRYPTO_MD5);
1296cdfce9ceSjonathan REGISTER(CRYPTO_SHA1);
1297ebc232a5Sdrochner REGISTER(CRYPTO_AES_XCBC_MAC_96);
12980a8dabdaSdrochner REGISTER(CRYPTO_AES_128_GMAC);
12990a8dabdaSdrochner REGISTER(CRYPTO_AES_192_GMAC);
13000a8dabdaSdrochner REGISTER(CRYPTO_AES_256_GMAC);
13018835ffd0Sriastradh REGISTER(CRYPTO_AES_CBC);
1302cdfce9ceSjonathan REGISTER(CRYPTO_DEFLATE_COMP);
13031caa9a52Sdrochner REGISTER(CRYPTO_DEFLATE_COMP_NOGROW);
130436ea3668Sdarran REGISTER(CRYPTO_GZIP_COMP);
1305cdfce9ceSjonathan #undef REGISTER
1306cdfce9ceSjonathan }
1307cdfce9ceSjonathan
13087bc6d90cSthorpej
13097bc6d90cSthorpej /*
13107bc6d90cSthorpej * Pseudo-device init routine for software crypto.
13117bc6d90cSthorpej */
13127bc6d90cSthorpej
13137bc6d90cSthorpej void
swcryptoattach(int num)1314168cd830Schristos swcryptoattach(int num)
13157bc6d90cSthorpej {
1316993fdeecSknakahara /*
131780c73109Sknakahara * swcrypto_attach() must be called after attached cpus, because
131880c73109Sknakahara * it calls softint_establish() through below call path.
131980c73109Sknakahara * swcr_init() => crypto_get_driverid() => crypto_init()
132080c73109Sknakahara * => crypto_init0()
132180c73109Sknakahara * If softint_establish() is called before attached cpus that ncpu == 0,
132280c73109Sknakahara * the softint handler is established to CPU#0 only.
132380c73109Sknakahara *
132480c73109Sknakahara * So, swcrypto_attach() must be called from not module_init_class()
132580c73109Sknakahara * but config_finalize() when it is built as builtin module.
1326993fdeecSknakahara */
132780c73109Sknakahara swcryptoattach_internal();
13287bc6d90cSthorpej }
13292dd4f4d9Spgoyette
13302dd4f4d9Spgoyette void swcrypto_attach(device_t, device_t, void *);
13312dd4f4d9Spgoyette
13322dd4f4d9Spgoyette void
swcrypto_attach(device_t parent,device_t self,void * opaque)13332dd4f4d9Spgoyette swcrypto_attach(device_t parent, device_t self, void *opaque)
13342dd4f4d9Spgoyette {
13352dd4f4d9Spgoyette
13362dd4f4d9Spgoyette swcr_init();
1337f43f371eSchristos
1338f43f371eSchristos if (!pmf_device_register(self, NULL, NULL))
1339f43f371eSchristos aprint_error_dev(self, "couldn't establish power handler\n");
13402dd4f4d9Spgoyette }
13412dd4f4d9Spgoyette
13422dd4f4d9Spgoyette int swcrypto_detach(device_t, int);
13432dd4f4d9Spgoyette
13442dd4f4d9Spgoyette int
swcrypto_detach(device_t self,int flag)13452dd4f4d9Spgoyette swcrypto_detach(device_t self, int flag)
13462dd4f4d9Spgoyette {
1347f1257be5Sriastradh pmf_device_deregister(self);
13482dd4f4d9Spgoyette if (swcr_id >= 0)
13492dd4f4d9Spgoyette crypto_unregister_all(swcr_id);
13502dd4f4d9Spgoyette return 0;
13512dd4f4d9Spgoyette }
13522dd4f4d9Spgoyette
13532dd4f4d9Spgoyette int swcrypto_match(device_t, cfdata_t, void *);
13542dd4f4d9Spgoyette
13552dd4f4d9Spgoyette int
swcrypto_match(device_t parent,cfdata_t data,void * opaque)13562dd4f4d9Spgoyette swcrypto_match(device_t parent, cfdata_t data, void *opaque)
13572dd4f4d9Spgoyette {
13582dd4f4d9Spgoyette
13592dd4f4d9Spgoyette return 1;
13602dd4f4d9Spgoyette }
13612dd4f4d9Spgoyette
13622dd4f4d9Spgoyette MODULE(MODULE_CLASS_DRIVER, swcrypto,
13632dd4f4d9Spgoyette "opencrypto,zlib,blowfish,des,cast128,camellia,skipjack");
13642dd4f4d9Spgoyette
13652dd4f4d9Spgoyette CFDRIVER_DECL(swcrypto, DV_DULL, NULL);
13662dd4f4d9Spgoyette
13672dd4f4d9Spgoyette CFATTACH_DECL2_NEW(swcrypto, 0, swcrypto_match, swcrypto_attach,
13682dd4f4d9Spgoyette swcrypto_detach, NULL, NULL, NULL);
13692dd4f4d9Spgoyette
13702dd4f4d9Spgoyette static int swcryptoloc[] = { -1, -1 };
13712dd4f4d9Spgoyette
13722dd4f4d9Spgoyette static struct cfdata swcrypto_cfdata[] = {
13732dd4f4d9Spgoyette {
13742dd4f4d9Spgoyette .cf_name = "swcrypto",
13752dd4f4d9Spgoyette .cf_atname = "swcrypto",
13762dd4f4d9Spgoyette .cf_unit = 0,
13772dd4f4d9Spgoyette .cf_fstate = 0,
13782dd4f4d9Spgoyette .cf_loc = swcryptoloc,
13792dd4f4d9Spgoyette .cf_flags = 0,
13802dd4f4d9Spgoyette .cf_pspec = NULL,
13812dd4f4d9Spgoyette },
13822dd4f4d9Spgoyette { NULL, NULL, 0, 0, NULL, 0, NULL }
13832dd4f4d9Spgoyette };
13842dd4f4d9Spgoyette
138580c73109Sknakahara /*
138680c73109Sknakahara * Internal attach routine.
138780c73109Sknakahara * Don't call before attached cpus.
138880c73109Sknakahara */
13892dd4f4d9Spgoyette static int
swcryptoattach_internal(void)139080c73109Sknakahara swcryptoattach_internal(void)
13912dd4f4d9Spgoyette {
13922dd4f4d9Spgoyette int error;
13932dd4f4d9Spgoyette
13942dd4f4d9Spgoyette error = config_cfdriver_attach(&swcrypto_cd);
13952dd4f4d9Spgoyette if (error) {
13962dd4f4d9Spgoyette return error;
13972dd4f4d9Spgoyette }
13982dd4f4d9Spgoyette
139980c73109Sknakahara error = config_cfattach_attach(swcrypto_cd.cd_name, &swcrypto_ca);
14002dd4f4d9Spgoyette if (error) {
14012dd4f4d9Spgoyette config_cfdriver_detach(&swcrypto_cd);
14022dd4f4d9Spgoyette aprint_error("%s: unable to register cfattach\n",
14032dd4f4d9Spgoyette swcrypto_cd.cd_name);
14042dd4f4d9Spgoyette
14052dd4f4d9Spgoyette return error;
14062dd4f4d9Spgoyette }
14072dd4f4d9Spgoyette
14082dd4f4d9Spgoyette error = config_cfdata_attach(swcrypto_cfdata, 1);
14092dd4f4d9Spgoyette if (error) {
14102dd4f4d9Spgoyette config_cfattach_detach(swcrypto_cd.cd_name,
14112dd4f4d9Spgoyette &swcrypto_ca);
14122dd4f4d9Spgoyette config_cfdriver_detach(&swcrypto_cd);
14132dd4f4d9Spgoyette aprint_error("%s: unable to register cfdata\n",
14142dd4f4d9Spgoyette swcrypto_cd.cd_name);
14152dd4f4d9Spgoyette
14162dd4f4d9Spgoyette return error;
14172dd4f4d9Spgoyette }
14182dd4f4d9Spgoyette
14192dd4f4d9Spgoyette (void)config_attach_pseudo(swcrypto_cfdata);
14202dd4f4d9Spgoyette
14212dd4f4d9Spgoyette return 0;
142280c73109Sknakahara }
142380c73109Sknakahara
142480c73109Sknakahara static int
swcrypto_modcmd(modcmd_t cmd,void * arg)142580c73109Sknakahara swcrypto_modcmd(modcmd_t cmd, void *arg)
142680c73109Sknakahara {
142780c73109Sknakahara int error = 0;
142880c73109Sknakahara
142980c73109Sknakahara switch (cmd) {
143080c73109Sknakahara case MODULE_CMD_INIT:
143180c73109Sknakahara #ifdef _MODULE
143280c73109Sknakahara error = swcryptoattach_internal();
143380c73109Sknakahara #endif
143480c73109Sknakahara return error;
14352dd4f4d9Spgoyette case MODULE_CMD_FINI:
1436d40a55d1Schristos #if 1
1437d40a55d1Schristos // XXX: Need to keep track if we are in use.
1438d40a55d1Schristos return ENOTTY;
1439d40a55d1Schristos #else
14402dd4f4d9Spgoyette error = config_cfdata_detach(swcrypto_cfdata);
14412dd4f4d9Spgoyette if (error) {
14422dd4f4d9Spgoyette return error;
14432dd4f4d9Spgoyette }
14442dd4f4d9Spgoyette
14452dd4f4d9Spgoyette config_cfattach_detach(swcrypto_cd.cd_name, &swcrypto_ca);
14462dd4f4d9Spgoyette config_cfdriver_detach(&swcrypto_cd);
14472dd4f4d9Spgoyette
14482dd4f4d9Spgoyette return 0;
1449d40a55d1Schristos #endif
14502dd4f4d9Spgoyette default:
14512dd4f4d9Spgoyette return ENOTTY;
14522dd4f4d9Spgoyette }
14532dd4f4d9Spgoyette }
1454