summaryrefslogtreecommitdiff
path: root/linux/net/ipsec/alg/ipsec_alg_cryptoapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/net/ipsec/alg/ipsec_alg_cryptoapi.c')
-rw-r--r--linux/net/ipsec/alg/ipsec_alg_cryptoapi.c421
1 files changed, 421 insertions, 0 deletions
diff --git a/linux/net/ipsec/alg/ipsec_alg_cryptoapi.c b/linux/net/ipsec/alg/ipsec_alg_cryptoapi.c
new file mode 100644
index 000000000..fc68094c2
--- /dev/null
+++ b/linux/net/ipsec/alg/ipsec_alg_cryptoapi.c
@@ -0,0 +1,421 @@
+/*
+ * ipsec_alg to linux cryptoapi GLUE
+ *
+ * Authors: CODE.ar TEAM
+ * Harpo MAxx <harpo@linuxmendoza.org.ar>
+ * JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ * Luciano Ruete <docemeses@softhome.net>
+ *
+ * $Id: ipsec_alg_cryptoapi.c,v 1.3 2004/09/17 18:57:30 as Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * Example usage:
+ * modinfo -p ipsec_cryptoapi (quite useful info, including supported algos)
+ * modprobe ipsec_cryptoapi
+ * modprobe ipsec_cryptoapi test=1
+ * modprobe ipsec_cryptoapi excl=1 (exclusive cipher/algo)
+ * modprobe ipsec_cryptoapi noauto=1 aes=1 twofish=1 (only these ciphers)
+ * modprobe ipsec_cryptoapi aes=128,128 (force these keylens)
+ * modprobe ipsec_cryptoapi des_ede3=0 (everything but 3DES)
+ */
+#include <linux/config.h>
+#include <linux/version.h>
+
+/*
+ * special case: ipsec core modular with this static algo inside:
+ * must avoid MODULE magic for this file
+ */
+#if CONFIG_IPSEC_MODULE && CONFIG_IPSEC_ALG_CRYPTOAPI
+#undef MODULE
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h> /* printk() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/string.h>
+
+/* Check if __exit is defined, if not null it */
+#ifndef __exit
+#define __exit
+#endif
+
+/* warn the innocent */
+#if !defined (CONFIG_CRYPTO) && !defined (CONFIG_CRYPTO_MODULE)
+#warning "No linux CryptoAPI found, install 2.4.22+ or 2.6.x"
+#define NO_CRYPTOAPI_SUPPORT
+#endif
+/* Low freeswan header coupling */
+#include "freeswan/ipsec_alg.h"
+
+#include <linux/crypto.h>
+#ifdef CRYPTO_API_VERSION_CODE
+#warning "Old CryptoAPI is not supported. Only linux-2.4.22+ or linux-2.6.x are supported"
+#define NO_CRYPTOAPI_SUPPORT
+#endif
+
+#ifdef NO_CRYPTOAPI_SUPPORT
+#warning "Building an unusable module :P"
+/* Catch old CryptoAPI by not allowing module to load */
+IPSEC_ALG_MODULE_INIT( ipsec_cryptoapi_init )
+{
+ printk(KERN_WARNING "ipsec_cryptoapi.o was not built on stock Linux CryptoAPI (2.4.22+ or 2.6.x), not loading.\n");
+ return -EINVAL;
+}
+#else
+#include <asm/scatterlist.h>
+#include <asm/pgtable.h>
+#include <linux/mm.h>
+
+#define CIPHERNAME_AES "aes"
+#define CIPHERNAME_3DES "des3_ede"
+#define CIPHERNAME_BLOWFISH "blowfish"
+#define CIPHERNAME_CAST "cast5"
+#define CIPHERNAME_SERPENT "serpent"
+#define CIPHERNAME_TWOFISH "twofish"
+
+#define ESP_3DES 3
+#define ESP_AES 12
+#define ESP_BLOWFISH 7 /* truly _constant_ :) */
+#define ESP_CAST 6 /* quite constant :) */
+#define ESP_SERPENT 252 /* from ipsec drafts */
+#define ESP_TWOFISH 253 /* from ipsec drafts */
+
+#define AH_MD5 2
+#define AH_SHA 3
+#define DIGESTNAME_MD5 "md5"
+#define DIGESTNAME_SHA1 "sha1"
+
+MODULE_AUTHOR("Juanjo Ciarlante, Harpo MAxx, Luciano Ruete");
+static int debug=0;
+MODULE_PARM(debug, "i");
+static int test=0;
+MODULE_PARM(test, "i");
+static int excl=0;
+MODULE_PARM(excl, "i");
+
+static int noauto = 0;
+MODULE_PARM(noauto,"i");
+MODULE_PARM_DESC(noauto, "Dont try all known algos, just setup enabled ones");
+
+static int des_ede3[] = {-1, -1};
+static int aes[] = {-1, -1};
+static int blowfish[] = {-1, -1};
+static int cast[] = {-1, -1};
+static int serpent[] = {-1, -1};
+static int twofish[] = {-1, -1};
+
+MODULE_PARM(des_ede3,"1-2i");
+MODULE_PARM(aes,"1-2i");
+MODULE_PARM(blowfish,"1-2i");
+MODULE_PARM(cast,"1-2i");
+MODULE_PARM(serpent,"1-2i");
+MODULE_PARM(twofish,"1-2i");
+MODULE_PARM_DESC(des_ede3, "0: disable | 1: force_enable | min,max: dontuse");
+MODULE_PARM_DESC(aes, "0: disable | 1: force_enable | min,max: keybitlens");
+MODULE_PARM_DESC(blowfish, "0: disable | 1: force_enable | min,max: keybitlens");
+MODULE_PARM_DESC(cast, "0: disable | 1: force_enable | min,max: keybitlens");
+MODULE_PARM_DESC(serpent, "0: disable | 1: force_enable | min,max: keybitlens");
+MODULE_PARM_DESC(twofish, "0: disable | 1: force_enable | min,max: keybitlens");
+
+struct ipsec_alg_capi_cipher {
+ const char *ciphername; /* cryptoapi's ciphername */
+ unsigned blocksize;
+ unsigned short minbits;
+ unsigned short maxbits;
+ int *parm; /* lkm param for this cipher */
+ struct ipsec_alg_enc alg; /* note it's not a pointer */
+};
+static struct ipsec_alg_capi_cipher alg_capi_carray[] = {
+ { CIPHERNAME_AES , 16, 128, 256, aes , { ixt_alg_id: ESP_AES, }},
+ { CIPHERNAME_TWOFISH , 16, 128, 256, twofish, { ixt_alg_id: ESP_TWOFISH, }},
+ { CIPHERNAME_SERPENT , 16, 128, 256, serpent, { ixt_alg_id: ESP_SERPENT, }},
+ { CIPHERNAME_CAST , 8, 128, 128, cast , { ixt_alg_id: ESP_CAST, }},
+ { CIPHERNAME_BLOWFISH , 8, 128, 448, blowfish,{ ixt_alg_id: ESP_BLOWFISH, }},
+ { CIPHERNAME_3DES , 8, 192, 192, des_ede3,{ ixt_alg_id: ESP_3DES, }},
+ { NULL, 0, 0, 0, NULL, {} }
+};
+#ifdef NOT_YET
+struct ipsec_alg_capi_digest {
+ const char *digestname; /* cryptoapi's digestname */
+ struct digest_implementation *di;
+ struct ipsec_alg_auth alg; /* note it's not a pointer */
+};
+static struct ipsec_alg_capi_cipher alg_capi_darray[] = {
+ { DIGESTNAME_MD5, NULL, { ixt_alg_id: AH_MD5, }},
+ { DIGESTNAME_SHA1, NULL, { ixt_alg_id: AH_SHA, }},
+ { NULL, NULL, {} }
+};
+#endif
+/*
+ * "generic" linux cryptoapi setup_cipher() function
+ */
+int setup_cipher(const char *ciphername)
+{
+ return crypto_alg_available(ciphername, 0);
+}
+
+/*
+ * setups ipsec_alg_capi_cipher "hyper" struct components, calling
+ * register_ipsec_alg for cointaned ipsec_alg object
+ */
+static void _capi_destroy_key (struct ipsec_alg_enc *alg, __u8 *key_e);
+static __u8 * _capi_new_key (struct ipsec_alg_enc *alg, const __u8 *key, size_t keylen);
+static int _capi_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt);
+
+static int
+setup_ipsec_alg_capi_cipher(struct ipsec_alg_capi_cipher *cptr)
+{
+ int ret;
+ cptr->alg.ixt_version = IPSEC_ALG_VERSION;
+ cptr->alg.ixt_module = THIS_MODULE;
+ atomic_set (& cptr->alg.ixt_refcnt, 0);
+ strncpy (cptr->alg.ixt_name , cptr->ciphername, sizeof (cptr->alg.ixt_name));
+
+ cptr->alg.ixt_blocksize=cptr->blocksize;
+ cptr->alg.ixt_keyminbits=cptr->minbits;
+ cptr->alg.ixt_keymaxbits=cptr->maxbits;
+ cptr->alg.ixt_state = 0;
+ if (excl) cptr->alg.ixt_state |= IPSEC_ALG_ST_EXCL;
+ cptr->alg.ixt_e_keylen=cptr->alg.ixt_keymaxbits/8;
+ cptr->alg.ixt_e_ctx_size = 0;
+ cptr->alg.ixt_alg_type = IPSEC_ALG_TYPE_ENCRYPT;
+ cptr->alg.ixt_e_new_key = _capi_new_key;
+ cptr->alg.ixt_e_destroy_key = _capi_destroy_key;
+ cptr->alg.ixt_e_cbc_encrypt = _capi_cbc_encrypt;
+ cptr->alg.ixt_data = cptr;
+
+ ret=register_ipsec_alg_enc(&cptr->alg);
+ printk("setup_ipsec_alg_capi_cipher(): "
+ "alg_type=%d alg_id=%d name=%s "
+ "keyminbits=%d keymaxbits=%d, ret=%d\n",
+ cptr->alg.ixt_alg_type,
+ cptr->alg.ixt_alg_id,
+ cptr->alg.ixt_name,
+ cptr->alg.ixt_keyminbits,
+ cptr->alg.ixt_keymaxbits,
+ ret);
+ return ret;
+}
+/*
+ * called in ipsec_sa_wipe() time, will destroy key contexts
+ * and do 1 unbind()
+ */
+static void
+_capi_destroy_key (struct ipsec_alg_enc *alg, __u8 *key_e)
+{
+ struct crypto_tfm *tfm=(struct crypto_tfm*)key_e;
+
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug: _capi_destroy_key:"
+ "name=%s key_e=%p \n",
+ alg->ixt_name, key_e);
+ if (!key_e) {
+ printk(KERN_ERR "klips_debug: _capi_destroy_key:"
+ "name=%s NULL key_e!\n",
+ alg->ixt_name);
+ return;
+ }
+ crypto_free_tfm(tfm);
+}
+
+/*
+ * create new key context, need alg->ixt_data to know which
+ * (of many) cipher inside this module is the target
+ */
+static __u8 *
+_capi_new_key (struct ipsec_alg_enc *alg, const __u8 *key, size_t keylen)
+{
+ struct ipsec_alg_capi_cipher *cptr;
+ struct crypto_tfm *tfm=NULL;
+
+ cptr = alg->ixt_data;
+ if (!cptr) {
+ printk(KERN_ERR "_capi_new_key(): "
+ "NULL ixt_data (?!) for \"%s\" algo\n"
+ , alg->ixt_name);
+ goto err;
+ }
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_capi_new_key:"
+ "name=%s cptr=%p key=%p keysize=%d\n",
+ alg->ixt_name, cptr, key, keylen);
+
+ /*
+ * alloc tfm
+ */
+ tfm = crypto_alloc_tfm(cptr->ciphername, CRYPTO_TFM_MODE_CBC);
+ if (!tfm) {
+ printk(KERN_ERR "_capi_new_key(): "
+ "NULL tfm for \"%s\" cryptoapi (\"%s\") algo\n"
+ , alg->ixt_name, cptr->ciphername);
+ goto err;
+ }
+ if (crypto_cipher_setkey(tfm, key, keylen) < 0) {
+ printk(KERN_ERR "_capi_new_key(): "
+ "failed new_key() for \"%s\" cryptoapi algo (keylen=%d)\n"
+ , alg->ixt_name, keylen);
+ crypto_free_tfm(tfm);
+ tfm=NULL;
+ }
+err:
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:_capi_new_key:"
+ "name=%s key=%p keylen=%d tfm=%p\n",
+ alg->ixt_name, key, keylen, tfm);
+ return (__u8 *) tfm;
+}
+/*
+ * core encryption function: will use cx->ci to call actual cipher's
+ * cbc function
+ */
+static int
+_capi_cbc_encrypt(struct ipsec_alg_enc *alg, __u8 * key_e, __u8 * in, int ilen, const __u8 * iv, int encrypt) {
+ int error =0;
+ struct crypto_tfm *tfm=(struct crypto_tfm *)key_e;
+ struct scatterlist sg = {
+ .page = virt_to_page(in),
+ .offset = (unsigned long)(in) % PAGE_SIZE,
+ .length=ilen,
+ };
+ if (debug > 1)
+ printk(KERN_DEBUG "klips_debug:_capi_cbc_encrypt:"
+ "key_e=%p "
+ "in=%p out=%p ilen=%d iv=%p encrypt=%d\n"
+ , key_e
+ , in, in, ilen, iv, encrypt);
+ crypto_cipher_set_iv(tfm, iv, crypto_tfm_alg_ivsize(tfm));
+ if (encrypt)
+ error = crypto_cipher_encrypt (tfm, &sg, &sg, ilen);
+ else
+ error = crypto_cipher_decrypt (tfm, &sg, &sg, ilen);
+ if (debug > 1)
+ printk(KERN_DEBUG "klips_debug:_capi_cbc_encrypt:"
+ "error=%d\n"
+ , error);
+ return (error<0)? error : ilen;
+}
+/*
+ * main initialization loop: for each cipher in list, do
+ * 1) setup cryptoapi cipher else continue
+ * 2) register ipsec_alg object
+ */
+static int
+setup_cipher_list (struct ipsec_alg_capi_cipher* clist)
+{
+ struct ipsec_alg_capi_cipher *cptr;
+ /* foreach cipher in list ... */
+ for (cptr=clist;cptr->ciphername;cptr++) {
+ /*
+ * see if cipher has been disabled (0) or
+ * if noauto set and not enabled (1)
+ */
+ if (cptr->parm[0] == 0 || (noauto && cptr->parm[0] < 0)) {
+ if (debug>0)
+ printk(KERN_INFO "setup_cipher_list(): "
+ "ciphername=%s skipped at user request: "
+ "noauto=%d parm[0]=%d parm[1]=%d\n"
+ , cptr->ciphername
+ , noauto
+ , cptr->parm[0]
+ , cptr->parm[1]);
+ continue;
+ }
+ /*
+ * use a local ci to avoid touching cptr->ci,
+ * if register ipsec_alg success then bind cipher
+ */
+ if( setup_cipher(cptr->ciphername) ) {
+ if (debug > 0)
+ printk(KERN_DEBUG "klips_debug:"
+ "setup_cipher_list():"
+ "ciphername=%s found\n"
+ , cptr->ciphername);
+ if (setup_ipsec_alg_capi_cipher(cptr) == 0) {
+
+
+ } else {
+ printk(KERN_ERR "klips_debug:"
+ "setup_cipher_list():"
+ "ciphername=%s failed ipsec_alg_register\n"
+ , cptr->ciphername);
+ }
+ } else {
+ if (debug>0)
+ printk(KERN_INFO "setup_cipher_list(): lookup for ciphername=%s: not found \n",
+ cptr->ciphername);
+ }
+ }
+ return 0;
+}
+/*
+ * deregister ipsec_alg objects and unbind ciphers
+ */
+static int
+unsetup_cipher_list (struct ipsec_alg_capi_cipher* clist)
+{
+ struct ipsec_alg_capi_cipher *cptr;
+ /* foreach cipher in list ... */
+ for (cptr=clist;cptr->ciphername;cptr++) {
+ if (cptr->alg.ixt_state & IPSEC_ALG_ST_REGISTERED) {
+ unregister_ipsec_alg_enc(&cptr->alg);
+ }
+ }
+ return 0;
+}
+/*
+ * test loop for registered algos
+ */
+static int
+test_cipher_list (struct ipsec_alg_capi_cipher* clist)
+{
+ int test_ret;
+ struct ipsec_alg_capi_cipher *cptr;
+ /* foreach cipher in list ... */
+ for (cptr=clist;cptr->ciphername;cptr++) {
+ if (cptr->alg.ixt_state & IPSEC_ALG_ST_REGISTERED) {
+ test_ret=ipsec_alg_test(
+ cptr->alg.ixt_alg_type,
+ cptr->alg.ixt_alg_id,
+ test);
+ printk("test_cipher_list(alg_type=%d alg_id=%d): test_ret=%d\n",
+ cptr->alg.ixt_alg_type,
+ cptr->alg.ixt_alg_id,
+ test_ret);
+ }
+ }
+ return 0;
+}
+
+IPSEC_ALG_MODULE_INIT( ipsec_cryptoapi_init )
+{
+ int ret, test_ret;
+ if ((ret=setup_cipher_list(alg_capi_carray)) < 0)
+ return -EPROTONOSUPPORT;
+ if (ret==0 && test) {
+ test_ret=test_cipher_list(alg_capi_carray);
+ }
+ return ret;
+}
+IPSEC_ALG_MODULE_EXIT( ipsec_cryptoapi_fini )
+{
+ unsetup_cipher_list(alg_capi_carray);
+ return;
+}
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+EXPORT_NO_SYMBOLS;
+#endif /* NO_CRYPTOAPI_SUPPORT */