cryptosoft.c revision 187826
190075Sobrien/*	$OpenBSD: cryptosoft.c,v 1.35 2002/04/26 08:43:50 deraadt Exp $	*/
290075Sobrien
3117395Skan/*-
490075Sobrien * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
590075Sobrien * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting
690075Sobrien *
790075Sobrien * This code was written by Angelos D. Keromytis in Athens, Greece, in
890075Sobrien * February 2000. Network Security Technologies Inc. (NSTI) kindly
990075Sobrien * supported the development of this code.
1090075Sobrien *
1190075Sobrien * Copyright (c) 2000, 2001 Angelos D. Keromytis
1290075Sobrien *
13132718Skan * Permission to use, copy, and modify this software with or without fee
1490075Sobrien * is hereby granted, provided that this entire notice is included in
1590075Sobrien * all source code copies of any software which is or includes a copy or
16146895Skan * modification of this software.
1790075Sobrien *
18146895Skan * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
19146895Skan * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
2090075Sobrien * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
21146895Skan * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
22146895Skan * PURPOSE.
23146895Skan */
24146895Skan
2590075Sobrien#include <sys/cdefs.h>
2690075Sobrien__FBSDID("$FreeBSD: head/sys/opencrypto/cryptosoft.c 187826 2009-01-28 15:31:16Z bz $");
2790075Sobrien
2890075Sobrien#include <sys/param.h>
2990075Sobrien#include <sys/systm.h>
30117395Skan#include <sys/malloc.h>
31117395Skan#include <sys/mbuf.h>
3290075Sobrien#include <sys/module.h>
3390075Sobrien#include <sys/sysctl.h>
3490075Sobrien#include <sys/errno.h>
3590075Sobrien#include <sys/random.h>
3690075Sobrien#include <sys/kernel.h>
3790075Sobrien#include <sys/uio.h>
3890075Sobrien
3996263Sobrien#include <crypto/blowfish/blowfish.h>
4090075Sobrien#include <crypto/sha1.h>
4190075Sobrien#include <opencrypto/rmd160.h>
4290075Sobrien#include <opencrypto/cast.h>
43104752Skan#include <opencrypto/skipjack.h>
4490075Sobrien#include <sys/md5.h>
4590075Sobrien
4690075Sobrien#include <opencrypto/cryptodev.h>
4790075Sobrien#include <opencrypto/cryptosoft.h>
4890075Sobrien#include <opencrypto/xform.h>
4990075Sobrien
5090075Sobrien#include <sys/kobj.h>
5190075Sobrien#include <sys/bus.h>
5290075Sobrien#include "cryptodev_if.h"
53132718Skan
54132718Skanstatic	int32_t swcr_id;
55132718Skanstatic	struct swcr_data **swcr_sessions = NULL;
56132718Skanstatic	u_int32_t swcr_sesnum;
57132718Skan
58132718Skanu_int8_t hmac_ipad_buffer[HMAC_MAX_BLOCK_LEN];
59132718Skanu_int8_t hmac_opad_buffer[HMAC_MAX_BLOCK_LEN];
60132718Skan
61132718Skanstatic	int swcr_encdec(struct cryptodesc *, struct swcr_data *, caddr_t, int);
62132718Skanstatic	int swcr_authcompute(struct cryptodesc *, struct swcr_data *, caddr_t, int);
6390075Sobrienstatic	int swcr_compdec(struct cryptodesc *, struct swcr_data *, caddr_t, int);
6490075Sobrienstatic	int swcr_freesession(device_t dev, u_int64_t tid);
6590075Sobrien
6690075Sobrien/*
6790075Sobrien * Apply a symmetric encryption/decryption algorithm.
6890075Sobrien */
6990075Sobrienstatic int
7090075Sobrienswcr_encdec(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf,
7190075Sobrien    int flags)
7290075Sobrien{
7390075Sobrien	unsigned char iv[EALG_MAX_BLOCK_LEN], blk[EALG_MAX_BLOCK_LEN], *idat;
7490075Sobrien	unsigned char *ivp, piv[EALG_MAX_BLOCK_LEN];
7590075Sobrien	struct enc_xform *exf;
7690075Sobrien	int i, k, j, blks;
77117395Skan
78117395Skan	exf = sw->sw_exf;
7990075Sobrien	blks = exf->blocksize;
8090075Sobrien
8190075Sobrien	/* Check for non-padded data */
82132718Skan	if (crd->crd_len % blks)
8390075Sobrien		return EINVAL;
84132718Skan
85132718Skan	/* Initialize the IV */
86132718Skan	if (crd->crd_flags & CRD_F_ENCRYPT) {
8790075Sobrien		/* IV explicitly provided ? */
8890075Sobrien		if (crd->crd_flags & CRD_F_IV_EXPLICIT)
8990075Sobrien			bcopy(crd->crd_iv, iv, blks);
9090075Sobrien		else
9190075Sobrien			arc4rand(iv, blks, 0);
9290075Sobrien
9390075Sobrien		/* Do we need to write the IV */
9490075Sobrien		if (!(crd->crd_flags & CRD_F_IV_PRESENT))
9590075Sobrien			crypto_copyback(flags, buf, crd->crd_inject, blks, iv);
9690075Sobrien
9790075Sobrien	} else {	/* Decryption */
9890075Sobrien			/* IV explicitly provided ? */
9990075Sobrien		if (crd->crd_flags & CRD_F_IV_EXPLICIT)
10090075Sobrien			bcopy(crd->crd_iv, iv, blks);
10190075Sobrien		else {
10290075Sobrien			/* Get IV off buf */
10390075Sobrien			crypto_copydata(flags, buf, crd->crd_inject, blks, iv);
10490075Sobrien		}
10590075Sobrien	}
106132718Skan
10790075Sobrien	if (crd->crd_flags & CRD_F_KEY_EXPLICIT) {
108132718Skan		int error;
109132718Skan
110132718Skan		if (sw->sw_kschedule)
11190075Sobrien			exf->zerokey(&(sw->sw_kschedule));
11290075Sobrien		error = exf->setkey(&sw->sw_kschedule,
11390075Sobrien				crd->crd_key, crd->crd_klen / 8);
11490075Sobrien		if (error)
11590075Sobrien			return (error);
11690075Sobrien	}
11790075Sobrien	ivp = iv;
11890075Sobrien
11990075Sobrien	if (flags & CRYPTO_F_IMBUF) {
12090075Sobrien		struct mbuf *m = (struct mbuf *) buf;
12190075Sobrien
12290075Sobrien		/* Find beginning of data */
12390075Sobrien		m = m_getptr(m, crd->crd_skip, &k);
124146895Skan		if (m == NULL)
125146895Skan			return EINVAL;
12690075Sobrien
127132718Skan		i = crd->crd_len;
12890075Sobrien
12990075Sobrien		while (i > 0) {
13090075Sobrien			/*
13190075Sobrien			 * If there's insufficient data at the end of
13290075Sobrien			 * an mbuf, we have to do some copying.
13390075Sobrien			 */
13490075Sobrien			if (m->m_len < k + blks && m->m_len != k) {
13590075Sobrien				m_copydata(m, k, blks, blk);
13690075Sobrien
13790075Sobrien				/* Actual encryption/decryption */
13890075Sobrien				if (crd->crd_flags & CRD_F_ENCRYPT) {
13990075Sobrien					/* XOR with previous block */
14090075Sobrien					for (j = 0; j < blks; j++)
14190075Sobrien						blk[j] ^= ivp[j];
14290075Sobrien
14390075Sobrien					exf->encrypt(sw->sw_kschedule, blk);
14490075Sobrien
14590075Sobrien					/*
14690075Sobrien					 * Keep encrypted block for XOR'ing
14790075Sobrien					 * with next block
14890075Sobrien					 */
14990075Sobrien					bcopy(blk, iv, blks);
15090075Sobrien					ivp = iv;
15190075Sobrien				} else {	/* decrypt */
15290075Sobrien					/*
15390075Sobrien					 * Keep encrypted block for XOR'ing
15490075Sobrien					 * with next block
15590075Sobrien					 */
15690075Sobrien					if (ivp == iv)
15790075Sobrien						bcopy(blk, piv, blks);
15890075Sobrien					else
15990075Sobrien						bcopy(blk, iv, blks);
16090075Sobrien
16190075Sobrien					exf->decrypt(sw->sw_kschedule, blk);
16290075Sobrien
16390075Sobrien					/* XOR with previous block */
16490075Sobrien					for (j = 0; j < blks; j++)
16590075Sobrien						blk[j] ^= ivp[j];
16690075Sobrien
16790075Sobrien					if (ivp == iv)
16890075Sobrien						bcopy(piv, iv, blks);
16990075Sobrien					else
17090075Sobrien						ivp = iv;
17190075Sobrien				}
17290075Sobrien
17390075Sobrien				/* Copy back decrypted block */
17490075Sobrien				m_copyback(m, k, blks, blk);
17590075Sobrien
17690075Sobrien				/* Advance pointer */
17790075Sobrien				m = m_getptr(m, k + blks, &k);
17890075Sobrien				if (m == NULL)
17990075Sobrien					return EINVAL;
18090075Sobrien
18190075Sobrien				i -= blks;
18290075Sobrien
18390075Sobrien				/* Could be done... */
18490075Sobrien				if (i == 0)
18590075Sobrien					break;
18690075Sobrien			}
18790075Sobrien
18890075Sobrien			/* Skip possibly empty mbufs */
18990075Sobrien			if (k == m->m_len) {
19090075Sobrien				for (m = m->m_next; m && m->m_len == 0;
19190075Sobrien				    m = m->m_next)
19290075Sobrien					;
19390075Sobrien				k = 0;
19490075Sobrien			}
19590075Sobrien
196117395Skan			/* Sanity check */
197117395Skan			if (m == NULL)
198117395Skan				return EINVAL;
199117395Skan
200117395Skan			/*
201117395Skan			 * Warning: idat may point to garbage here, but
202117395Skan			 * we only use it in the while() loop, only if
203117395Skan			 * there are indeed enough data.
204117395Skan			 */
205117395Skan			idat = mtod(m, unsigned char *) + k;
206117395Skan
207117395Skan	   		while (m->m_len >= k + blks && i > 0) {
208117395Skan				if (crd->crd_flags & CRD_F_ENCRYPT) {
209117395Skan					/* XOR with previous block/IV */
210117395Skan					for (j = 0; j < blks; j++)
21190075Sobrien						idat[j] ^= ivp[j];
21290075Sobrien
21390075Sobrien					exf->encrypt(sw->sw_kschedule, idat);
21490075Sobrien					ivp = idat;
21590075Sobrien				} else {	/* decrypt */
21690075Sobrien					/*
21790075Sobrien					 * Keep encrypted block to be used
21890075Sobrien					 * in next block's processing.
21990075Sobrien					 */
22090075Sobrien					if (ivp == iv)
22190075Sobrien						bcopy(idat, piv, blks);
22290075Sobrien					else
22390075Sobrien						bcopy(idat, iv, blks);
22490075Sobrien
22590075Sobrien					exf->decrypt(sw->sw_kschedule, idat);
22690075Sobrien
22790075Sobrien					/* XOR with previous block/IV */
22890075Sobrien					for (j = 0; j < blks; j++)
22990075Sobrien						idat[j] ^= ivp[j];
23090075Sobrien
23190075Sobrien					if (ivp == iv)
23290075Sobrien						bcopy(piv, iv, blks);
23390075Sobrien					else
23490075Sobrien						ivp = iv;
23590075Sobrien				}
23690075Sobrien
23790075Sobrien				idat += blks;
23890075Sobrien				k += blks;
23990075Sobrien				i -= blks;
24090075Sobrien			}
24190075Sobrien		}
24290075Sobrien
24390075Sobrien		return 0; /* Done with mbuf encryption/decryption */
244146895Skan	} else if (flags & CRYPTO_F_IOV) {
24590075Sobrien		struct uio *uio = (struct uio *) buf;
24690075Sobrien		struct iovec *iov;
24790075Sobrien
24890075Sobrien		/* Find beginning of data */
249146895Skan		iov = cuio_getptr(uio, crd->crd_skip, &k);
250146895Skan		if (iov == NULL)
251146895Skan			return EINVAL;
252146895Skan
253146895Skan		i = crd->crd_len;
254146895Skan
255146895Skan		while (i > 0) {
256146895Skan			/*
257146895Skan			 * If there's insufficient data at the end of
258146895Skan			 * an iovec, we have to do some copying.
259146895Skan			 */
260146895Skan			if (iov->iov_len < k + blks && iov->iov_len != k) {
261146895Skan				cuio_copydata(uio, k, blks, blk);
262146895Skan
263146895Skan				/* Actual encryption/decryption */
264146895Skan				if (crd->crd_flags & CRD_F_ENCRYPT) {
26590075Sobrien					/* XOR with previous block */
26690075Sobrien					for (j = 0; j < blks; j++)
26790075Sobrien						blk[j] ^= ivp[j];
26890075Sobrien
26990075Sobrien					exf->encrypt(sw->sw_kschedule, blk);
27090075Sobrien
27190075Sobrien					/*
27290075Sobrien					 * Keep encrypted block for XOR'ing
27390075Sobrien					 * with next block
27490075Sobrien					 */
27590075Sobrien					bcopy(blk, iv, blks);
27690075Sobrien					ivp = iv;
27790075Sobrien				} else {	/* decrypt */
27890075Sobrien					/*
27990075Sobrien					 * Keep encrypted block for XOR'ing
28090075Sobrien					 * with next block
28190075Sobrien					 */
28290075Sobrien					if (ivp == iv)
283146895Skan						bcopy(blk, piv, blks);
284146895Skan					else
285146895Skan						bcopy(blk, iv, blks);
286146895Skan
287146895Skan					exf->decrypt(sw->sw_kschedule, blk);
288146895Skan
289146895Skan					/* XOR with previous block */
290146895Skan					for (j = 0; j < blks; j++)
291146895Skan						blk[j] ^= ivp[j];
292146895Skan
293146895Skan					if (ivp == iv)
294146895Skan						bcopy(piv, iv, blks);
295146895Skan					else
296146895Skan						ivp = iv;
297146895Skan				}
298146895Skan
299146895Skan				/* Copy back decrypted block */
300146895Skan				cuio_copyback(uio, k, blks, blk);
301146895Skan
302146895Skan				/* Advance pointer */
303146895Skan				iov = cuio_getptr(uio, k + blks, &k);
304146895Skan				if (iov == NULL)
305146895Skan					return EINVAL;
306146895Skan
307146895Skan				i -= blks;
308146895Skan
309146895Skan				/* Could be done... */
310146895Skan				if (i == 0)
311146895Skan					break;
312146895Skan			}
313146895Skan
314146895Skan			/*
315146895Skan			 * Warning: idat may point to garbage here, but
316146895Skan			 * we only use it in the while() loop, only if
317146895Skan			 * there are indeed enough data.
318146895Skan			 */
319146895Skan			idat = (char *)iov->iov_base + k;
320146895Skan
321146895Skan	   		while (iov->iov_len >= k + blks && i > 0) {
322146895Skan				if (crd->crd_flags & CRD_F_ENCRYPT) {
323146895Skan					/* XOR with previous block/IV */
324146895Skan					for (j = 0; j < blks; j++)
325146895Skan						idat[j] ^= ivp[j];
326146895Skan
327146895Skan					exf->encrypt(sw->sw_kschedule, idat);
328132718Skan					ivp = idat;
329132718Skan				} else {	/* decrypt */
330132718Skan					/*
331132718Skan					 * Keep encrypted block to be used
332132718Skan					 * in next block's processing.
333132718Skan					 */
334132718Skan					if (ivp == iv)
335132718Skan						bcopy(idat, piv, blks);
336132718Skan					else
337132718Skan						bcopy(idat, iv, blks);
338132718Skan
339132718Skan					exf->decrypt(sw->sw_kschedule, idat);
340132718Skan
341132718Skan					/* XOR with previous block/IV */
342132718Skan					for (j = 0; j < blks; j++)
343132718Skan						idat[j] ^= ivp[j];
344132718Skan
345132718Skan					if (ivp == iv)
346132718Skan						bcopy(piv, iv, blks);
34790075Sobrien					else
34896263Sobrien						ivp = iv;
34990075Sobrien				}
35090075Sobrien
35190075Sobrien				idat += blks;
35290075Sobrien				k += blks;
35390075Sobrien				i -= blks;
35490075Sobrien			}
355146895Skan			if (k == iov->iov_len) {
356146895Skan				iov++;
35790075Sobrien				k = 0;
35890075Sobrien			}
35990075Sobrien		}
36090075Sobrien
36190075Sobrien		return 0; /* Done with iovec encryption/decryption */
36290075Sobrien	} else {	/* contiguous buffer */
363146895Skan		if (crd->crd_flags & CRD_F_ENCRYPT) {
364146895Skan			for (i = crd->crd_skip;
36590075Sobrien			    i < crd->crd_skip + crd->crd_len; i += blks) {
366146895Skan				/* XOR with the IV/previous block, as appropriate. */
367146895Skan				if (i == crd->crd_skip)
368146895Skan					for (k = 0; k < blks; k++)
369146895Skan						buf[i + k] ^= ivp[k];
370146895Skan				else
371146895Skan					for (k = 0; k < blks; k++)
372146895Skan						buf[i + k] ^= buf[i + k - blks];
37390075Sobrien				exf->encrypt(sw->sw_kschedule, buf + i);
37490075Sobrien			}
37590075Sobrien		} else {		/* Decrypt */
37690075Sobrien			/*
37790075Sobrien			 * Start at the end, so we don't need to keep the encrypted
37890075Sobrien			 * block as the IV for the next block.
37990075Sobrien			 */
380132718Skan			for (i = crd->crd_skip + crd->crd_len - blks;
381132718Skan			    i >= crd->crd_skip; i -= blks) {
382132718Skan				exf->decrypt(sw->sw_kschedule, buf + i);
383132718Skan
384146895Skan				/* XOR with the IV/previous block, as appropriate */
385146895Skan				if (i == crd->crd_skip)
386146895Skan					for (k = 0; k < blks; k++)
387146895Skan						buf[i + k] ^= ivp[k];
388146895Skan				else
389146895Skan					for (k = 0; k < blks; k++)
390146895Skan						buf[i + k] ^= buf[i + k - blks];
391146895Skan			}
392146895Skan		}
393146895Skan
394146895Skan		return 0; /* Done with contiguous buffer encryption/decryption */
395146895Skan	}
396132718Skan
39796263Sobrien	/* Unreachable */
39896263Sobrien	return EINVAL;
39996263Sobrien}
400132718Skan
401132718Skanstatic void
402132718Skanswcr_authprepare(struct auth_hash *axf, struct swcr_data *sw, u_char *key,
403132718Skan    int klen)
404132718Skan{
405132718Skan	int k;
406132718Skan
407132718Skan	klen /= 8;
408132718Skan
409132718Skan	switch (axf->type) {
410132718Skan	case CRYPTO_MD5_HMAC:
411132718Skan	case CRYPTO_SHA1_HMAC:
412132718Skan	case CRYPTO_SHA2_256_HMAC:
413132718Skan	case CRYPTO_SHA2_384_HMAC:
41490075Sobrien	case CRYPTO_SHA2_512_HMAC:
41590075Sobrien	case CRYPTO_NULL_HMAC:
41690075Sobrien	case CRYPTO_RIPEMD160_HMAC:
41790075Sobrien		for (k = 0; k < klen; k++)
41890075Sobrien			key[k] ^= HMAC_IPAD_VAL;
41990075Sobrien
42090075Sobrien		axf->Init(sw->sw_ictx);
42190075Sobrien		axf->Update(sw->sw_ictx, key, klen);
42290075Sobrien		axf->Update(sw->sw_ictx, hmac_ipad_buffer, axf->blocksize - klen);
42396263Sobrien
42496263Sobrien		for (k = 0; k < klen; k++)
42596263Sobrien			key[k] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
42696263Sobrien
42796263Sobrien		axf->Init(sw->sw_octx);
428132718Skan		axf->Update(sw->sw_octx, key, klen);
429132718Skan		axf->Update(sw->sw_octx, hmac_opad_buffer, axf->blocksize - klen);
430132718Skan
431132718Skan		for (k = 0; k < klen; k++)
43296263Sobrien			key[k] ^= HMAC_OPAD_VAL;
43396263Sobrien		break;
43496263Sobrien	case CRYPTO_MD5_KPDK:
435132718Skan	case CRYPTO_SHA1_KPDK:
436132718Skan	{
437132718Skan		/* We need a buffer that can hold an md5 and a sha1 result. */
438132718Skan		u_char buf[SHA1_RESULTLEN];
43996263Sobrien
44096263Sobrien		sw->sw_klen = klen;
44196263Sobrien		bcopy(key, sw->sw_octx, klen);
44296263Sobrien		axf->Init(sw->sw_ictx);
443122180Skan		axf->Update(sw->sw_ictx, key, klen);
444122180Skan		axf->Final(buf, sw->sw_ictx);
445122180Skan		break;
446122180Skan	}
447122180Skan	default:
448122180Skan		printf("%s: CRD_F_KEY_EXPLICIT flag given, but algorithm %d "
44990075Sobrien		    "doesn't use keys.\n", __func__, axf->type);
450122180Skan	}
45190075Sobrien}
45296263Sobrien
453132718Skan/*
45490075Sobrien * Compute keyed-hash authenticator.
455132718Skan */
456132718Skanstatic int
457132718Skanswcr_authcompute(struct cryptodesc *crd, struct swcr_data *sw, caddr_t buf,
458132718Skan    int flags)
459132718Skan{
460132718Skan	unsigned char aalg[HASH_MAX_LEN];
461146895Skan	struct auth_hash *axf;
462146895Skan	union authctx ctx;
463146895Skan	int err;
464146895Skan
465146895Skan	if (sw->sw_ictx == 0)
466146895Skan		return EINVAL;
467146895Skan
468146895Skan	axf = sw->sw_axf;
469146895Skan
470146895Skan	if (crd->crd_flags & CRD_F_KEY_EXPLICIT)
47190075Sobrien		swcr_authprepare(axf, sw, crd->crd_key, crd->crd_klen);
47290075Sobrien
47390075Sobrien	bcopy(sw->sw_ictx, &ctx, axf->ctxsize);
474146895Skan
47590075Sobrien	err = crypto_apply(flags, buf, crd->crd_skip, crd->crd_len,
476146895Skan	    (int (*)(void *, void *, unsigned int))axf->Update, (caddr_t)&ctx);
477132718Skan	if (err)
47890075Sobrien		return err;
47990075Sobrien
48096263Sobrien	switch (sw->sw_alg) {
48196263Sobrien	case CRYPTO_MD5_HMAC:
482146895Skan	case CRYPTO_SHA1_HMAC:
48390075Sobrien	case CRYPTO_SHA2_256_HMAC:
48490075Sobrien	case CRYPTO_SHA2_384_HMAC:
485146895Skan	case CRYPTO_SHA2_512_HMAC:
48690075Sobrien	case CRYPTO_RIPEMD160_HMAC:
48796263Sobrien		if (sw->sw_octx == NULL)
488146895Skan			return EINVAL;
489146895Skan
490146895Skan		axf->Final(aalg, &ctx);
491146895Skan		bcopy(sw->sw_octx, &ctx, axf->ctxsize);
49296263Sobrien		axf->Update(&ctx, aalg, axf->hashsize);
493132718Skan		axf->Final(aalg, &ctx);
494104752Skan		break;
49596263Sobrien
496104752Skan	case CRYPTO_MD5_KPDK:
497104752Skan	case CRYPTO_SHA1_KPDK:
49896263Sobrien		if (sw->sw_octx == NULL)
499104752Skan			return EINVAL;
500104752Skan
501104752Skan		axf->Update(&ctx, sw->sw_octx, sw->sw_klen);
502104752Skan		axf->Final(aalg, &ctx);
503146895Skan		break;
504132718Skan
505132718Skan	case CRYPTO_NULL_HMAC:
506132718Skan		axf->Final(aalg, &ctx);
507104752Skan		break;
508104752Skan	}
509146895Skan
510132718Skan	/* Inject the authentication data */
511104752Skan	crypto_copyback(flags, buf, crd->crd_inject,
51296263Sobrien	    sw->sw_mlen == 0 ? axf->hashsize : sw->sw_mlen, aalg);
51396263Sobrien	return 0;
51490075Sobrien}
51590075Sobrien
51690075Sobrien/*
51790075Sobrien * Apply a compression/decompression algorithm
51890075Sobrien */
51990075Sobrienstatic int
52090075Sobrienswcr_compdec(struct cryptodesc *crd, struct swcr_data *sw,
52196263Sobrien    caddr_t buf, int flags)
52296263Sobrien{
523132718Skan	u_int8_t *data, *out;
524132718Skan	struct comp_algo *cxf;
525146895Skan	int adj;
526146895Skan	u_int32_t result;
527146895Skan
528146895Skan	cxf = sw->sw_cxf;
529146895Skan
530146895Skan	/* We must handle the whole buffer of data in one time
531146895Skan	 * then if there is not all the data in the mbuf, we must
532146895Skan	 * copy in a buffer.
533146895Skan	 */
534146895Skan
535146895Skan	data = malloc(crd->crd_len, M_CRYPTO_DATA,  M_NOWAIT);
536146895Skan	if (data == NULL)
53790075Sobrien		return (EINVAL);
53890075Sobrien	crypto_copydata(flags, buf, crd->crd_skip, crd->crd_len, data);
539146895Skan
54090075Sobrien	if (crd->crd_flags & CRD_F_COMP)
54190075Sobrien		result = cxf->compress(data, crd->crd_len, &out);
54290075Sobrien	else
54390075Sobrien		result = cxf->decompress(data, crd->crd_len, &out);
54490075Sobrien
54590075Sobrien	free(data, M_CRYPTO_DATA);
54690075Sobrien	if (result == 0)
54796263Sobrien		return EINVAL;
54896263Sobrien
549132718Skan	/* Copy back the (de)compressed data. m_copyback is
550132718Skan	 * extending the mbuf as necessary.
551146895Skan	 */
552146895Skan	sw->sw_size = result;
553146895Skan	/* Check the compressed size when doing compression */
554146895Skan	if (crd->crd_flags & CRD_F_COMP) {
555146895Skan		if (result > crd->crd_len) {
556146895Skan			/* Compression was useless, we lost time */
557146895Skan			free(out, M_CRYPTO_DATA);
558146895Skan			return 0;
559146895Skan		}
560146895Skan	}
561146895Skan
562146895Skan	crypto_copyback(flags, buf, crd->crd_skip, result, out);
56390075Sobrien	if (result < crd->crd_len) {
56490075Sobrien		adj = result - crd->crd_len;
56590075Sobrien		if (flags & CRYPTO_F_IMBUF) {
56690075Sobrien			adj = result - crd->crd_len;
56790075Sobrien			m_adj((struct mbuf *)buf, adj);
56890075Sobrien		} else if (flags & CRYPTO_F_IOV) {
56990075Sobrien			struct uio *uio = (struct uio *)buf;
57090075Sobrien			int ind;
571132718Skan
57290075Sobrien			adj = crd->crd_len - result;
57390075Sobrien			ind = uio->uio_iovcnt - 1;
57490075Sobrien
57590075Sobrien			while (adj > 0 && ind >= 0) {
57690075Sobrien				if (adj < uio->uio_iov[ind].iov_len) {
577132718Skan					uio->uio_iov[ind].iov_len -= adj;
57890075Sobrien					break;
57990075Sobrien				}
58090075Sobrien
581146895Skan				adj -= uio->uio_iov[ind].iov_len;
582132718Skan				uio->uio_iov[ind].iov_len = 0;
583132718Skan				ind--;
58490075Sobrien				uio->uio_iovcnt--;
58590075Sobrien			}
58690075Sobrien		}
58790075Sobrien	}
58890075Sobrien	free(out, M_CRYPTO_DATA);
58990075Sobrien	return 0;
59090075Sobrien}
59190075Sobrien
59290075Sobrien/*
59390075Sobrien * Generate a new software session.
59490075Sobrien */
595132718Skanstatic int
596146895Skanswcr_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri)
597146895Skan{
598146895Skan	struct swcr_data **swd;
59990075Sobrien	struct auth_hash *axf;
60090075Sobrien	struct enc_xform *txf;
60190075Sobrien	struct comp_algo *cxf;
60290075Sobrien	u_int32_t i;
60390075Sobrien	int error;
60490075Sobrien
60590075Sobrien	if (sid == NULL || cri == NULL)
60690075Sobrien		return EINVAL;
60790075Sobrien
608146895Skan	if (swcr_sessions) {
609146895Skan		for (i = 1; i < swcr_sesnum; i++)
610146895Skan			if (swcr_sessions[i] == NULL)
61190075Sobrien				break;
61290075Sobrien	} else
613146895Skan		i = 1;		/* NB: to silence compiler warning */
614146895Skan
615146895Skan	if (swcr_sessions == NULL || i == swcr_sesnum) {
61690075Sobrien		if (swcr_sessions == NULL) {
61790075Sobrien			i = 1; /* We leave swcr_sessions[0] empty */
61890075Sobrien			swcr_sesnum = CRYPTO_SW_SESSIONS;
61990075Sobrien		} else
62090075Sobrien			swcr_sesnum *= 2;
62190075Sobrien
62290075Sobrien		swd = malloc(swcr_sesnum * sizeof(struct swcr_data *),
62390075Sobrien		    M_CRYPTO_DATA, M_NOWAIT|M_ZERO);
62490075Sobrien		if (swd == NULL) {
62590075Sobrien			/* Reset session number */
62690075Sobrien			if (swcr_sesnum == CRYPTO_SW_SESSIONS)
62790075Sobrien				swcr_sesnum = 0;
62890075Sobrien			else
62990075Sobrien				swcr_sesnum /= 2;
63090075Sobrien			return ENOBUFS;
63190075Sobrien		}
63290075Sobrien
63390075Sobrien		/* Copy existing sessions */
63490075Sobrien		if (swcr_sessions != NULL) {
63590075Sobrien			bcopy(swcr_sessions, swd,
63690075Sobrien			    (swcr_sesnum / 2) * sizeof(struct swcr_data *));
63790075Sobrien			free(swcr_sessions, M_CRYPTO_DATA);
63890075Sobrien		}
63990075Sobrien
64090075Sobrien		swcr_sessions = swd;
64190075Sobrien	}
64290075Sobrien
64390075Sobrien	swd = &swcr_sessions[i];
64490075Sobrien	*sid = i;
64590075Sobrien
64690075Sobrien	while (cri) {
64790075Sobrien		*swd = malloc(sizeof(struct swcr_data),
64890075Sobrien		    M_CRYPTO_DATA, M_NOWAIT|M_ZERO);
64990075Sobrien		if (*swd == NULL) {
65090075Sobrien			swcr_freesession(dev, i);
65190075Sobrien			return ENOBUFS;
65290075Sobrien		}
65390075Sobrien
65490075Sobrien		switch (cri->cri_alg) {
65590075Sobrien		case CRYPTO_DES_CBC:
656104752Skan			txf = &enc_xform_des;
65790075Sobrien			goto enccommon;
658110611Skan		case CRYPTO_3DES_CBC:
659132718Skan			txf = &enc_xform_3des;
66090075Sobrien			goto enccommon;
661110611Skan		case CRYPTO_BLF_CBC:
66290075Sobrien			txf = &enc_xform_blf;
66390075Sobrien			goto enccommon;
66490075Sobrien		case CRYPTO_CAST_CBC:
665132718Skan			txf = &enc_xform_cast5;
666132718Skan			goto enccommon;
66790075Sobrien		case CRYPTO_SKIPJACK_CBC:
66890075Sobrien			txf = &enc_xform_skipjack;
66990075Sobrien			goto enccommon;
67090075Sobrien		case CRYPTO_RIJNDAEL128_CBC:
67190075Sobrien			txf = &enc_xform_rijndael128;
67290075Sobrien			goto enccommon;
67396263Sobrien		case CRYPTO_CAMELLIA_CBC:
67496263Sobrien			txf = &enc_xform_camellia;
675146895Skan			goto enccommon;
67690075Sobrien		case CRYPTO_NULL_CBC:
67790075Sobrien			txf = &enc_xform_null;
678146895Skan			goto enccommon;
67990075Sobrien		enccommon:
68096263Sobrien			if (cri->cri_key != NULL) {
681146895Skan				error = txf->setkey(&((*swd)->sw_kschedule),
68296263Sobrien				    cri->cri_key, cri->cri_klen / 8);
68396263Sobrien				if (error) {
684104752Skan					swcr_freesession(dev, i);
685104752Skan					return error;
686104752Skan				}
68796263Sobrien			}
68896263Sobrien			(*swd)->sw_exf = txf;
68996263Sobrien			break;
690104752Skan
691104752Skan		case CRYPTO_MD5_HMAC:
692104752Skan			axf = &auth_hash_hmac_md5;
693104752Skan			goto authcommon;
694146895Skan		case CRYPTO_SHA1_HMAC:
695104752Skan			axf = &auth_hash_hmac_sha1;
696104752Skan			goto authcommon;
697104752Skan		case CRYPTO_SHA2_256_HMAC:
698104752Skan			axf = &auth_hash_hmac_sha2_256;
699104752Skan			goto authcommon;
700146895Skan		case CRYPTO_SHA2_384_HMAC:
701104752Skan			axf = &auth_hash_hmac_sha2_384;
70296263Sobrien			goto authcommon;
70396263Sobrien		case CRYPTO_SHA2_512_HMAC:
70490075Sobrien			axf = &auth_hash_hmac_sha2_512;
70596263Sobrien			goto authcommon;
70696263Sobrien		case CRYPTO_NULL_HMAC:
70796263Sobrien			axf = &auth_hash_null;
70896263Sobrien			goto authcommon;
709146895Skan		case CRYPTO_RIPEMD160_HMAC:
710146895Skan			axf = &auth_hash_hmac_ripemd_160;
711146895Skan		authcommon:
712146895Skan			(*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
713146895Skan			    M_NOWAIT);
714146895Skan			if ((*swd)->sw_ictx == NULL) {
715146895Skan				swcr_freesession(dev, i);
716146895Skan				return ENOBUFS;
717146895Skan			}
718146895Skan
71990075Sobrien			(*swd)->sw_octx = malloc(axf->ctxsize, M_CRYPTO_DATA,
72090075Sobrien			    M_NOWAIT);
72190075Sobrien			if ((*swd)->sw_octx == NULL) {
72296263Sobrien				swcr_freesession(dev, i);
72396263Sobrien				return ENOBUFS;
72496263Sobrien			}
72596263Sobrien
726146895Skan			if (cri->cri_key != NULL) {
727146895Skan				swcr_authprepare(axf, *swd, cri->cri_key,
728146895Skan				    cri->cri_klen);
729146895Skan			}
730146895Skan
731146895Skan			(*swd)->sw_mlen = cri->cri_mlen;
732146895Skan			(*swd)->sw_axf = axf;
733146895Skan			break;
734146895Skan
735146895Skan		case CRYPTO_MD5_KPDK:
73690075Sobrien			axf = &auth_hash_key_md5;
73790075Sobrien			goto auth2common;
73890075Sobrien
73990075Sobrien		case CRYPTO_SHA1_KPDK:
74090075Sobrien			axf = &auth_hash_key_sha1;
74190075Sobrien		auth2common:
74290075Sobrien			(*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
74390075Sobrien			    M_NOWAIT);
744110611Skan			if ((*swd)->sw_ictx == NULL) {
74590075Sobrien				swcr_freesession(dev, i);
74690075Sobrien				return ENOBUFS;
747110611Skan			}
74890075Sobrien
74990075Sobrien			(*swd)->sw_octx = malloc(cri->cri_klen / 8,
75090075Sobrien			    M_CRYPTO_DATA, M_NOWAIT);
75190075Sobrien			if ((*swd)->sw_octx == NULL) {
752				swcr_freesession(dev, i);
753				return ENOBUFS;
754			}
755
756			/* Store the key so we can "append" it to the payload */
757			if (cri->cri_key != NULL) {
758				swcr_authprepare(axf, *swd, cri->cri_key,
759				    cri->cri_klen);
760			}
761
762			(*swd)->sw_mlen = cri->cri_mlen;
763			(*swd)->sw_axf = axf;
764			break;
765#ifdef notdef
766		case CRYPTO_MD5:
767			axf = &auth_hash_md5;
768			goto auth3common;
769
770		case CRYPTO_SHA1:
771			axf = &auth_hash_sha1;
772		auth3common:
773			(*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA,
774			    M_NOWAIT);
775			if ((*swd)->sw_ictx == NULL) {
776				swcr_freesession(dev, i);
777				return ENOBUFS;
778			}
779
780			axf->Init((*swd)->sw_ictx);
781			(*swd)->sw_mlen = cri->cri_mlen;
782			(*swd)->sw_axf = axf;
783			break;
784#endif
785		case CRYPTO_DEFLATE_COMP:
786			cxf = &comp_algo_deflate;
787			(*swd)->sw_cxf = cxf;
788			break;
789		default:
790			swcr_freesession(dev, i);
791			return EINVAL;
792		}
793
794		(*swd)->sw_alg = cri->cri_alg;
795		cri = cri->cri_next;
796		swd = &((*swd)->sw_next);
797	}
798	return 0;
799}
800
801/*
802 * Free a session.
803 */
804static int
805swcr_freesession(device_t dev, u_int64_t tid)
806{
807	struct swcr_data *swd;
808	struct enc_xform *txf;
809	struct auth_hash *axf;
810	struct comp_algo *cxf;
811	u_int32_t sid = CRYPTO_SESID2LID(tid);
812
813	if (sid > swcr_sesnum || swcr_sessions == NULL ||
814	    swcr_sessions[sid] == NULL)
815		return EINVAL;
816
817	/* Silently accept and return */
818	if (sid == 0)
819		return 0;
820
821	while ((swd = swcr_sessions[sid]) != NULL) {
822		swcr_sessions[sid] = swd->sw_next;
823
824		switch (swd->sw_alg) {
825		case CRYPTO_DES_CBC:
826		case CRYPTO_3DES_CBC:
827		case CRYPTO_BLF_CBC:
828		case CRYPTO_CAST_CBC:
829		case CRYPTO_SKIPJACK_CBC:
830		case CRYPTO_RIJNDAEL128_CBC:
831		case CRYPTO_CAMELLIA_CBC:
832		case CRYPTO_NULL_CBC:
833			txf = swd->sw_exf;
834
835			if (swd->sw_kschedule)
836				txf->zerokey(&(swd->sw_kschedule));
837			break;
838
839		case CRYPTO_MD5_HMAC:
840		case CRYPTO_SHA1_HMAC:
841		case CRYPTO_SHA2_256_HMAC:
842		case CRYPTO_SHA2_384_HMAC:
843		case CRYPTO_SHA2_512_HMAC:
844		case CRYPTO_RIPEMD160_HMAC:
845		case CRYPTO_NULL_HMAC:
846			axf = swd->sw_axf;
847
848			if (swd->sw_ictx) {
849				bzero(swd->sw_ictx, axf->ctxsize);
850				free(swd->sw_ictx, M_CRYPTO_DATA);
851			}
852			if (swd->sw_octx) {
853				bzero(swd->sw_octx, axf->ctxsize);
854				free(swd->sw_octx, M_CRYPTO_DATA);
855			}
856			break;
857
858		case CRYPTO_MD5_KPDK:
859		case CRYPTO_SHA1_KPDK:
860			axf = swd->sw_axf;
861
862			if (swd->sw_ictx) {
863				bzero(swd->sw_ictx, axf->ctxsize);
864				free(swd->sw_ictx, M_CRYPTO_DATA);
865			}
866			if (swd->sw_octx) {
867				bzero(swd->sw_octx, swd->sw_klen);
868				free(swd->sw_octx, M_CRYPTO_DATA);
869			}
870			break;
871
872		case CRYPTO_MD5:
873		case CRYPTO_SHA1:
874			axf = swd->sw_axf;
875
876			if (swd->sw_ictx)
877				free(swd->sw_ictx, M_CRYPTO_DATA);
878			break;
879
880		case CRYPTO_DEFLATE_COMP:
881			cxf = swd->sw_cxf;
882			break;
883		}
884
885		free(swd, M_CRYPTO_DATA);
886	}
887	return 0;
888}
889
890/*
891 * Process a software request.
892 */
893static int
894swcr_process(device_t dev, struct cryptop *crp, int hint)
895{
896	struct cryptodesc *crd;
897	struct swcr_data *sw;
898	u_int32_t lid;
899
900	/* Sanity check */
901	if (crp == NULL)
902		return EINVAL;
903
904	if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
905		crp->crp_etype = EINVAL;
906		goto done;
907	}
908
909	lid = crp->crp_sid & 0xffffffff;
910	if (lid >= swcr_sesnum || lid == 0 || swcr_sessions[lid] == NULL) {
911		crp->crp_etype = ENOENT;
912		goto done;
913	}
914
915	/* Go through crypto descriptors, processing as we go */
916	for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
917		/*
918		 * Find the crypto context.
919		 *
920		 * XXX Note that the logic here prevents us from having
921		 * XXX the same algorithm multiple times in a session
922		 * XXX (or rather, we can but it won't give us the right
923		 * XXX results). To do that, we'd need some way of differentiating
924		 * XXX between the various instances of an algorithm (so we can
925		 * XXX locate the correct crypto context).
926		 */
927		for (sw = swcr_sessions[lid];
928		    sw && sw->sw_alg != crd->crd_alg;
929		    sw = sw->sw_next)
930			;
931
932		/* No such context ? */
933		if (sw == NULL) {
934			crp->crp_etype = EINVAL;
935			goto done;
936		}
937		switch (sw->sw_alg) {
938		case CRYPTO_DES_CBC:
939		case CRYPTO_3DES_CBC:
940		case CRYPTO_BLF_CBC:
941		case CRYPTO_CAST_CBC:
942		case CRYPTO_SKIPJACK_CBC:
943		case CRYPTO_RIJNDAEL128_CBC:
944		case CRYPTO_CAMELLIA_CBC:
945			if ((crp->crp_etype = swcr_encdec(crd, sw,
946			    crp->crp_buf, crp->crp_flags)) != 0)
947				goto done;
948			break;
949		case CRYPTO_NULL_CBC:
950			crp->crp_etype = 0;
951			break;
952		case CRYPTO_MD5_HMAC:
953		case CRYPTO_SHA1_HMAC:
954		case CRYPTO_SHA2_256_HMAC:
955		case CRYPTO_SHA2_384_HMAC:
956		case CRYPTO_SHA2_512_HMAC:
957		case CRYPTO_RIPEMD160_HMAC:
958		case CRYPTO_NULL_HMAC:
959		case CRYPTO_MD5_KPDK:
960		case CRYPTO_SHA1_KPDK:
961		case CRYPTO_MD5:
962		case CRYPTO_SHA1:
963			if ((crp->crp_etype = swcr_authcompute(crd, sw,
964			    crp->crp_buf, crp->crp_flags)) != 0)
965				goto done;
966			break;
967
968		case CRYPTO_DEFLATE_COMP:
969			if ((crp->crp_etype = swcr_compdec(crd, sw,
970			    crp->crp_buf, crp->crp_flags)) != 0)
971				goto done;
972			else
973				crp->crp_olen = (int)sw->sw_size;
974			break;
975
976		default:
977			/* Unknown/unsupported algorithm */
978			crp->crp_etype = EINVAL;
979			goto done;
980		}
981	}
982
983done:
984	crypto_done(crp);
985	return 0;
986}
987
988static void
989swcr_identify(device_t *dev, device_t parent)
990{
991	/* NB: order 10 is so we get attached after h/w devices */
992	if (device_find_child(parent, "cryptosoft", -1) == NULL &&
993	    BUS_ADD_CHILD(parent, 10, "cryptosoft", -1) == 0)
994		panic("cryptosoft: could not attach");
995}
996
997static int
998swcr_probe(device_t dev)
999{
1000	device_set_desc(dev, "software crypto");
1001	return (0);
1002}
1003
1004static int
1005swcr_attach(device_t dev)
1006{
1007	memset(hmac_ipad_buffer, HMAC_IPAD_VAL, HMAC_MAX_BLOCK_LEN);
1008	memset(hmac_opad_buffer, HMAC_OPAD_VAL, HMAC_MAX_BLOCK_LEN);
1009
1010	swcr_id = crypto_get_driverid(dev,
1011			CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC);
1012	if (swcr_id < 0) {
1013		device_printf(dev, "cannot initialize!");
1014		return ENOMEM;
1015	}
1016#define	REGISTER(alg) \
1017	crypto_register(swcr_id, alg, 0,0)
1018	REGISTER(CRYPTO_DES_CBC);
1019	REGISTER(CRYPTO_3DES_CBC);
1020	REGISTER(CRYPTO_BLF_CBC);
1021	REGISTER(CRYPTO_CAST_CBC);
1022	REGISTER(CRYPTO_SKIPJACK_CBC);
1023	REGISTER(CRYPTO_NULL_CBC);
1024	REGISTER(CRYPTO_MD5_HMAC);
1025	REGISTER(CRYPTO_SHA1_HMAC);
1026	REGISTER(CRYPTO_SHA2_256_HMAC);
1027	REGISTER(CRYPTO_SHA2_384_HMAC);
1028	REGISTER(CRYPTO_SHA2_512_HMAC);
1029	REGISTER(CRYPTO_RIPEMD160_HMAC);
1030	REGISTER(CRYPTO_NULL_HMAC);
1031	REGISTER(CRYPTO_MD5_KPDK);
1032	REGISTER(CRYPTO_SHA1_KPDK);
1033	REGISTER(CRYPTO_MD5);
1034	REGISTER(CRYPTO_SHA1);
1035	REGISTER(CRYPTO_RIJNDAEL128_CBC);
1036 	REGISTER(CRYPTO_CAMELLIA_CBC);
1037	REGISTER(CRYPTO_DEFLATE_COMP);
1038#undef REGISTER
1039
1040	return 0;
1041}
1042
1043static void
1044swcr_detach(device_t dev)
1045{
1046	crypto_unregister_all(swcr_id);
1047	if (swcr_sessions != NULL)
1048		free(swcr_sessions, M_CRYPTO_DATA);
1049}
1050
1051static device_method_t swcr_methods[] = {
1052	DEVMETHOD(device_identify,	swcr_identify),
1053	DEVMETHOD(device_probe,		swcr_probe),
1054	DEVMETHOD(device_attach,	swcr_attach),
1055	DEVMETHOD(device_detach,	swcr_detach),
1056
1057	DEVMETHOD(cryptodev_newsession,	swcr_newsession),
1058	DEVMETHOD(cryptodev_freesession,swcr_freesession),
1059	DEVMETHOD(cryptodev_process,	swcr_process),
1060
1061	{0, 0},
1062};
1063
1064static driver_t swcr_driver = {
1065	"cryptosoft",
1066	swcr_methods,
1067	0,		/* NB: no softc */
1068};
1069static devclass_t swcr_devclass;
1070
1071/*
1072 * NB: We explicitly reference the crypto module so we
1073 * get the necessary ordering when built as a loadable
1074 * module.  This is required because we bundle the crypto
1075 * module code together with the cryptosoft driver (otherwise
1076 * normal module dependencies would handle things).
1077 */
1078extern int crypto_modevent(struct module *, int, void *);
1079/* XXX where to attach */
1080DRIVER_MODULE(cryptosoft, nexus, swcr_driver, swcr_devclass, crypto_modevent,0);
1081MODULE_VERSION(cryptosoft, 1);
1082MODULE_DEPEND(cryptosoft, crypto, 1, 1, 1);
1083