⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipsec_alg.c

📁 This a good VPN source
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Modular extensions service and registration functions * * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar> *  * Version: 0.8.1 * * ipsec_alg.c,v 1.1.2.1 2003/11/21 18:12:23 jjo 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. * */#define __NO_VERSION__#include <linux/module.h>#include <linux/kernel.h> /* printk() */#include <linux/netdevice.h>   /* struct device, and other headers */#include <linux/etherdevice.h> /* eth_type_trans */#include <linux/ip.h>          /* struct iphdr */#include <linux/skbuff.h>#include <linux/socket.h>#include <linux/in.h>#include <linux/types.h>#include <linux/string.h>	/* memcmp() */#include <linux/random.h>	/* get_random_bytes() */#include <linux/errno.h>  /* error codes */#ifdef SPINLOCK# ifdef SPINLOCK_23#  include <linux/spinlock.h> /* *lock* */# else /* SPINLOCK_23 */#  include <asm/spinlock.h> /* *lock* */# endif /* SPINLOCK_23 */#endif /* SPINLOCK */#ifdef NET_21# include <asm/uaccess.h># include <linux/in6.h># define proto_priv cb#endif /* NET21 */#include "openswan/ipsec_param.h"#include <openswan.h>#include "openswan/ipsec_sa.h"#include "openswan/radij.h"#include "openswan/ipsec_encap.h"#include "openswan/ipsec_radij.h"#include "openswan/ipsec_xform.h"#include "openswan/ipsec_tunnel.h"#include "openswan/ipsec_rcv.h"#if defined(CONFIG_KLIPS_ESP) || defined(CONFIG_KLIPS_AH)# include "openswan/ipsec_ah.h"#endif /* defined(CONFIG_KLIPS_ESP) || defined(CONFIG_KLIPS_AH) */#ifdef CONFIG_KLIPS_ESP# include "openswan/ipsec_esp.h"#endif /* !CONFIG_KLIPS_ESP */#ifdef CONFIG_KLIPS_IPCOMP# include "openswan/ipcomp.h"#endif /* CONFIG_KLIPS_COMP */#include <pfkeyv2.h>#include <pfkey.h>#include "openswan/ipsec_alg.h"#ifndef CONFIG_KLIPS_ALG#error This file _MUST_ be compiled with CONFIG_KLIPS_ALG enabled !#endif#if SADB_EALG_MAX < 255#warning Compiling with limited ESP support ( SADB_EALG_MAX < 256 )#endifstatic rwlock_t ipsec_alg_lock = RW_LOCK_UNLOCKED;#define IPSEC_ALG_HASHSZ	16	/* must be power of 2, even 2^0=1 */static struct list_head ipsec_alg_hash_table[IPSEC_ALG_HASHSZ];/*	Old gcc's will fail here 	*/#define barf_out(fmt, args...)  do { printk(KERN_ERR "%s: (%s) " fmt, __FUNCTION__, ixt->ixt_name , ## args)\	; goto out; } while(0)#ifdef NET_26/*  * 	Must be already protected by lock  */static void __ipsec_alg_usage_inc(struct ipsec_alg *ixt) {	if (ixt->ixt_module)		try_module_get(ixt->ixt_module);	atomic_inc(&ixt->ixt_refcnt);}static void __ipsec_alg_usage_dec(struct ipsec_alg *ixt) {	atomic_dec(&ixt->ixt_refcnt);	if (ixt->ixt_module)		module_put(ixt->ixt_module);}#else/*  * 	Must be already protected by lock  */static void __ipsec_alg_usage_inc(struct ipsec_alg *ixt) {	if (ixt->ixt_module) {		__MOD_INC_USE_COUNT(ixt->ixt_module);	}	atomic_inc(&ixt->ixt_refcnt);}static void __ipsec_alg_usage_dec(struct ipsec_alg *ixt) {	atomic_dec(&ixt->ixt_refcnt);	if (ixt->ixt_module)		__MOD_DEC_USE_COUNT(ixt->ixt_module);}#endif/* * 	simple hash function, optimized for 0-hash (1 list) special * 	case */#if IPSEC_ALG_HASHSZ > 1static inline unsigned ipsec_alg_hashfn(int alg_type, int alg_id) {	return ((alg_type^alg_id)&(IPSEC_ALG_HASHSZ-1));}#else#define ipsec_alg_hashfn(x,y) (0)#endif/***************************************************************** * * 	INTERNAL table handling: insert, delete, find * *****************************************************************//*	 *	hash table initialization, called from ipsec_alg_init() */static void ipsec_alg_hash_init(void) {	struct list_head *head = ipsec_alg_hash_table;	int i = IPSEC_ALG_HASHSZ;	do {		INIT_LIST_HEAD(head);		head++;		i--;	} while (i);}/* * 	hash list lookup by {alg_type, alg_id} and table head, * 	must be already protected by lock */static struct ipsec_alg *__ipsec_alg_find(unsigned alg_type, unsigned alg_id, struct list_head * head) {	struct list_head *p;	struct ipsec_alg *ixt=NULL;	for (p=head->next; p!=head; p=p->next) {		ixt = list_entry(p, struct ipsec_alg, ixt_list);		if (ixt->ixt_alg_type == alg_type && ixt->ixt_alg_id==alg_id) {			goto out;		}	}	ixt=NULL;out:	return ixt;}/* * 	inserts (in front) a new entry in hash table,  * 	called from ipsec_alg_register() when new algorithm is registered. */static int ipsec_alg_insert(struct ipsec_alg *ixt) {	int ret=-EINVAL;	unsigned hashval=ipsec_alg_hashfn(ixt->ixt_alg_type, ixt->ixt_alg_id);	struct list_head *head= ipsec_alg_hash_table + hashval;	struct ipsec_alg *ixt_cur;	/* 	new element must be virgin ... */	if (ixt->ixt_list.next != &ixt->ixt_list || 		ixt->ixt_list.prev != &ixt->ixt_list) {		printk(KERN_ERR "ipsec_alg_insert: ixt object \"%s\" "				"list head not initialized\n",				ixt->ixt_name);		return ret;	}	write_lock_bh(&ipsec_alg_lock);	ixt_cur = __ipsec_alg_find(ixt->ixt_alg_type, ixt->ixt_alg_id, head);	/* if previous (current) ipsec_alg found check excl flag of _anyone_ */	if (ixt_cur && ((ixt->ixt_state|ixt_cur->ixt_state) & IPSEC_ALG_ST_EXCL))		barf_out("ipsec_alg for alg_type=%d, alg_id=%d already exist. "				"Not loaded (ret=%d).\n",				ixt->ixt_alg_type,				ixt->ixt_alg_id, ret=-EEXIST);	list_add(&ixt->ixt_list, head);	ixt->ixt_state |= IPSEC_ALG_ST_REGISTERED;	ret=0;out:	write_unlock_bh(&ipsec_alg_lock);	return ret;}/* * 	deletes an existing entry in hash table,  * 	called from ipsec_alg_unregister() when algorithm is unregistered. */static int ipsec_alg_delete(struct ipsec_alg *ixt) {	write_lock_bh(&ipsec_alg_lock);	list_del(&ixt->ixt_list);	write_unlock_bh(&ipsec_alg_lock);	return 0;}/* * 	here @user context (read-only when @kernel bh context)  * 	-> no bh disabling * * 	called from ipsec_sa_init() -> ipsec_alg_sa_init() */static struct ipsec_alg *ipsec_alg_get(int alg_type, int alg_id) {	unsigned hashval=ipsec_alg_hashfn(alg_type, alg_id);	struct list_head *head= ipsec_alg_hash_table + hashval;	struct ipsec_alg *ixt;	read_lock(&ipsec_alg_lock);	ixt=__ipsec_alg_find(alg_type, alg_id, head);	if (ixt) __ipsec_alg_usage_inc(ixt);	read_unlock(&ipsec_alg_lock);	return ixt;}static void ipsec_alg_put(struct ipsec_alg *ixt) {	__ipsec_alg_usage_dec((struct ipsec_alg *)ixt);}/***************************************************************** * * 	INTERFACE for ENC services: key creation, encrypt function * *****************************************************************//* * 	main encrypt service entry point * 	called from ipsec_rcv() with encrypt=IPSEC_ALG_DECRYPT and * 	ipsec_tunnel_start_xmit with encrypt=IPSEC_ALG_ENCRYPT */int ipsec_alg_esp_encrypt(struct ipsec_sa *sa_p, __u8 * idat, int ilen, const __u8 * iv, int encrypt) {	int ret;	struct ipsec_alg_enc *ixt_e=sa_p->ips_alg_enc;	KLIPS_PRINT(debug_rcv||debug_tunnel,		    "klips_debug:ipsec_alg_esp_encrypt: "		    "entering with encalg=%d, ixt_e=%p\n",		    sa_p->ips_encalg, ixt_e);	if (!ixt_e) {		KLIPS_PRINT(debug_rcv||debug_tunnel,			    "klips_debug:ipsec_alg_esp_encrypt: "			    "NULL ipsec_alg_enc object\n");		return -1;	}	KLIPS_PRINT(debug_rcv||debug_tunnel,		    "klips_debug:ipsec_alg_esp_encrypt: "		    "calling cbc_encrypt encalg=%d "		    "ips_key_e=%p idat=%p ilen=%d iv=%p, encrypt=%d\n",			sa_p->ips_encalg, 			sa_p->ips_key_e, idat, ilen, iv, encrypt);	ret=ixt_e->ixt_e_cbc_encrypt(ixt_e, sa_p->ips_key_e, idat, ilen, iv, encrypt);	KLIPS_PRINT(debug_rcv||debug_tunnel,		    "klips_debug:ipsec_alg_esp_encrypt: "		    "returned ret=%d\n",		    ret);	return ret;}/* * 	encryption key context creation function * 	called from pfkey_v2_parser.c:pfkey_ips_init()  */int ipsec_alg_enc_key_create(struct ipsec_sa *sa_p) {	int ret=-EINVAL;	int keyminbits, keymaxbits;	caddr_t ekp;	struct ipsec_alg_enc *ixt_e=sa_p->ips_alg_enc;	KLIPS_PRINT(debug_pfkey,		    "klips_debug:ipsec_alg_enc_key_create: "		    "entering with encalg=%d ixt_e=%p\n",		    sa_p->ips_encalg, ixt_e);	if (!ixt_e) {		KLIPS_PRINT(debug_pfkey,			    "klips_debug:ipsec_alg_enc_key_create: "			    "NULL ipsec_alg_enc object\n");		return -EPROTO;	}	/* 	 * grRRR... DES 7bits jurassic stuff ... f*ckk --jjo 	 */	switch(ixt_e->ixt_alg_id) {		case ESP_3DES:			keyminbits=keymaxbits=192;break;		case ESP_DES:			keyminbits=keymaxbits=64;break;		default:			keyminbits=ixt_e->ixt_keyminbits;			keymaxbits=ixt_e->ixt_keymaxbits;	}	if(sa_p->ips_key_bits_e<keyminbits || 			sa_p->ips_key_bits_e>keymaxbits) {		KLIPS_PRINT(debug_pfkey,				"klips_debug:ipsec_alg_enc_key_create: "				"incorrect encryption key size for id=%d: %d bits -- "				"must be between %d,%d bits\n" /*octets (bytes)\n"*/,				ixt_e->ixt_alg_id,				sa_p->ips_key_bits_e, keyminbits, keymaxbits);		ret=-EINVAL;		goto ixt_out;	}	/* save encryption key pointer */	ekp = sa_p->ips_key_e;	if (ixt_e->ixt_e_new_key) {		sa_p->ips_key_e = ixt_e->ixt_e_new_key(ixt_e,				ekp, sa_p->ips_key_bits_e/8);		ret =  (sa_p->ips_key_e)? 0 : -EINVAL;	} else {		if((sa_p->ips_key_e = (caddr_t)		    kmalloc((sa_p->ips_key_e_size = ixt_e->ixt_e_ctx_size),			    GFP_ATOMIC)) == NULL) {			ret=-ENOMEM;			goto ixt_out;		}		/* zero-out key_e */		memset(sa_p->ips_key_e, 0, sa_p->ips_key_e_size);		/* I cast here to allow more decoupling in alg module */		KLIPS_PRINT(debug_pfkey,			    "klips_debug:ipsec_alg_enc_key_create: about to call:"				    "set_key(key_e=%p, ekp=%p, key_size=%d)\n",				    (caddr_t)sa_p->ips_key_e, ekp, sa_p->ips_key_bits_e/8);		ret = ixt_e->ixt_e_set_key(ixt_e, (caddr_t)sa_p->ips_key_e, ekp, sa_p->ips_key_bits_e/8);	}	/* paranoid */	memset(ekp, 0, sa_p->ips_key_bits_e/8);	kfree(ekp);ixt_out:	return ret;}/*************************************************************** * * 	INTERFACE for AUTH services: key creation, hash functions * ***************************************************************//* * 	auth key context creation function * 	called from pfkey_v2_parser.c:pfkey_ips_init()  */int ipsec_alg_auth_key_create(struct ipsec_sa *sa_p) {	int ret=-EINVAL;	struct ipsec_alg_auth *ixt_a=sa_p->ips_alg_auth;	int keyminbits, keymaxbits;	unsigned char *akp;	unsigned int aks;	KLIPS_PRINT(debug_pfkey,		    "klips_debug:ipsec_alg_auth_key_create: "		    "entering with authalg=%d ixt_a=%p\n",		    sa_p->ips_authalg, ixt_a);	if (!ixt_a) {		KLIPS_PRINT(debug_pfkey,			    "klips_debug:ipsec_alg_auth_key_create: "			    "NULL ipsec_alg_auth object\n");		return -EPROTO;	}	keyminbits=ixt_a->ixt_keyminbits;	keymaxbits=ixt_a->ixt_keymaxbits;	if(sa_p->ips_key_bits_a<keyminbits || sa_p->ips_key_bits_a>keymaxbits) {		KLIPS_PRINT(debug_pfkey,			    "klips_debug:ipsec_alg_auth_key_create: incorrect auth"			    "key size: %d bits -- must be between %d,%d bits\n"/*octets (bytes)\n"*/,			    sa_p->ips_key_bits_a, keyminbits, keymaxbits);		ret=-EINVAL;		goto ixt_out;	}	/* save auth key pointer */	sa_p->ips_auth_bits = ixt_a->ixt_a_keylen * 8; /* XXX XXX */	akp = sa_p->ips_key_a;	aks = sa_p->ips_key_a_size;	/* will hold: 2 ctx and a blocksize buffer: kb */	sa_p->ips_key_a_size = ixt_a->ixt_a_ctx_size;	if((sa_p->ips_key_a = 		(caddr_t) kmalloc(sa_p->ips_key_a_size, GFP_ATOMIC)) == NULL) {		ret=-ENOMEM;		goto ixt_out;	}	ixt_a->ixt_a_hmac_set_key(ixt_a, sa_p->ips_key_a, akp, sa_p->ips_key_bits_a/8); /* XXX XXX */	ret=0;	memset(akp, 0, aks);	kfree(akp);			ixt_out:	return ret;}int ipsec_alg_sa_esp_hash(const struct ipsec_sa *sa_p, const __u8 *espp, int len, __u8 *hash, int hashlen) {	struct ipsec_alg_auth *ixt_a=sa_p->ips_alg_auth;	if (!ixt_a) {		KLIPS_PRINT(debug_pfkey,			    "klips_debug:ipsec_sa_esp_hash: "			    "NULL ipsec_alg_auth object\n");		return -EPROTO;	}	KLIPS_PRINT(debug_tunnel|debug_rcv,			"klips_debug:ipsec_sa_esp_hash: "			"hashing %p (%d bytes) to %p (%d bytes)\n",			espp, len,			hash, hashlen);	ixt_a->ixt_a_hmac_hash(ixt_a,			sa_p->ips_key_a, 			espp, len,			hash, hashlen);	return 0;}/*************************************************************** * * 	INTERFACE for module loading,testing, and unloading * ***************************************************************//* validation for registering (enc) module */static int check_enc(struct ipsec_alg_enc *ixt) {	int ret=-EINVAL;	if (ixt->ixt_blocksize==0) /*  || ixt->ixt_blocksize%2) need for ESP_NULL */		barf_out(KERN_ERR "invalid blocksize=%d\n", ixt->ixt_blocksize);	if (ixt->ixt_keyminbits==0 && ixt->ixt_keymaxbits==0 && ixt->ixt_e_keylen==0)		goto zero_key_ok;	if (ixt->ixt_keyminbits==0)		barf_out(KERN_ERR "invalid keyminbits=%d\n", ixt->ixt_keyminbits);	if (ixt->ixt_keymaxbits==0)		barf_out(KERN_ERR "invalid keymaxbits=%d\n", ixt->ixt_keymaxbits);	if (ixt->ixt_e_keylen==0)		barf_out(KERN_ERR "invalid keysize=%d\n", ixt->ixt_e_keylen);zero_key_ok:	if (ixt->ixt_e_ctx_size==0 && ixt->ixt_e_new_key == NULL)		barf_out(KERN_ERR "invalid key_e_size=%d and ixt_e_new_key=NULL\n", ixt->ixt_e_ctx_size);	if (ixt->ixt_e_cbc_encrypt==NULL)		barf_out(KERN_ERR "e_cbc_encrypt() must be not NULL\n");	ret=0;out:	return ret;}/* validation for registering (auth) module */static int check_auth(struct ipsec_alg_auth *ixt){	int ret=-EINVAL;	if (ixt->ixt_alg_id==0 || ixt->ixt_alg_id > SADB_AALG_MAX)		barf_out("invalid alg_id=%d > %d (SADB_AALG_MAX)\n", ixt->ixt_alg_id, SADB_AALG_MAX);	if (ixt->ixt_blocksize==0 || ixt->ixt_blocksize%2)		barf_out(KERN_ERR "invalid blocksize=%d\n", ixt->ixt_blocksize);	if (ixt->ixt_blocksize>AH_BLKLEN_MAX)		barf_out(KERN_ERR "sorry blocksize=%d > %d. "			"Please increase AH_BLKLEN_MAX and recompile\n", 			ixt->ixt_blocksize,			AH_BLKLEN_MAX);	if (ixt->ixt_keyminbits==0 && ixt->ixt_keymaxbits==0 && ixt->ixt_a_keylen==0)		goto zero_key_ok;	if (ixt->ixt_keyminbits==0)		barf_out(KERN_ERR "invalid keyminbits=%d\n", ixt->ixt_keyminbits);	if (ixt->ixt_keymaxbits==0)		barf_out(KERN_ERR "invalid keymaxbits=%d\n", ixt->ixt_keymaxbits);	if (ixt->ixt_keymaxbits!=ixt->ixt_keyminbits)		barf_out(KERN_ERR "keymaxbits must equal keyminbits (not sure).\n");	if (ixt->ixt_a_keylen==0)		barf_out(KERN_ERR "invalid keysize=%d\n", ixt->ixt_a_keylen);zero_key_ok:	if (ixt->ixt_a_ctx_size==0)		barf_out(KERN_ERR "invalid a_ctx_size=%d\n", ixt->ixt_a_ctx_size);	if (ixt->ixt_a_hmac_set_key==NULL)		barf_out(KERN_ERR "a_hmac_set_key() must be not NULL\n");	if (ixt->ixt_a_hmac_hash==NULL)		barf_out(KERN_ERR "a_hmac_hash() must be not NULL\n");	ret=0;out:	return ret;}/*  * Generic (enc, auth) registration entry point  */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -