Index: freeswan/pluto/Makefile
diff -u freeswan/pluto/Makefile:1.1.1.1.6.2 freeswan/pluto/Makefile:1.1.1.1.6.1.2.3
--- freeswan/pluto/Makefile:1.1.1.1.6.2	Fri Jul  5 00:16:22 2002
+++ freeswan/pluto/Makefile	Fri Jul  5 00:35:30 2002
@@ -128,6 +128,9 @@
 	id.c id.h \
 	ipsec_doi.c ipsec_doi.h \
 	kernel.c kernel.h \
+	kernel_alg.c kernel_alg.h \
+	ike_alg.c ike_alg.h \
+	alg_info.c alg_info.h \
 	kernel_comm.c kernel_comm.h \
 	log.c log.h \
 	main.c \
@@ -176,7 +179,26 @@
 	$(INSTALL) $(INSTMANFLAGS) ipsec.secrets.5 $(FMANDIR)
 	../utils/manlink $(FMANDIR) ipsec.secrets.5
 
-$(BINNAMEPLUTO): $(OBJSPLUTO)
+alg_info_test: alg_info_test.o alg_info.o kernel_alg.o ike_alg.o constants.o defs.o log.o db_ops.o crypto.o $(LIBDESLITE) $(FREESWANLIB)
+	$(CC) -o $@ $^ $(LIBSPLUTO)
+
+# alg/libalg.o contains an already resolved object built with
+# additional crypto algos inside.
+OBJSPLUTO:= kernel_alg.o ike_alg.o alg_info.o db_ops.o $(OBJSPLUTO) alg/libalg.o 
+# if new alg source is created in alg directory,
+# trigger libalg.o rebuild
+alg/libalg.o: alg
+	make -C alg libalg.o
+	touch alg/libalg.o
+
+# helper for creating alg/Make.common
+showdefs:
+	@echo DEFINES=$(DEFINES)
+	@echo CFLAGS=$(CFLAGS)
+	@echo CPPFLAGS=$(CPPFLAGS)
+	@echo COPTS=$(COPTS)
+
+$(BINNAMEPLUTO): $(OBJSPLUTO) $(ALG_LIBS)
 	$(CC) -o $(BINNAMEPLUTO) $(LDFLAGS) $(OBJSPLUTO) $(LIBSPLUTO)
 
 $(BINNAMEADNS): $(OBJSADNS)
@@ -208,6 +230,7 @@
 		$(OBJSPLUTO) $(BINNAMEPLUTO) \
 		$(OBJSWHACK) $(BINNAMEWHACK) \
 		$(OBJSADNS) $(BINNAMEADNS)
+	make -C alg clean
 
 check:
 	echo no checks in lib right now.
@@ -243,6 +266,7 @@
 # Dependencies generated by "make gatherdeps":
 adns.o: adns.c
 asn1.o: asn1.c
+alg_info.o: alg_info.c
 connections.o: connections.c
 constants.o: constants.c
 cookie.o: cookie.c
@@ -254,7 +278,9 @@
 elgamal.o: elgamal.c
 gcryptfix.o: gcryptfix.c
 id.o: id.c
+ike_alg.o: ike_alg.c
 ipsec_doi.o: ipsec_doi.c
+kernel_alg.o: kernel_alg.c
 kernel.o: kernel.c
 kernel_comm.o: kernel_comm.c
 log.o: log.c
@@ -283,6 +309,14 @@
 asn1.o: asn1.h
 asn1.o: log.h
 asn1.o: pem.h
+alg_info.o: alg_info.h
+alg_info.o: constants.h
+alg_info.o: defs.h
+alg_info.o: log.h
+alg_info.o: kernel_alg.h
+alg_info.o: sha1.h
+alg_info.o: md5.h
+alg_info.o: crypto.h
 connections.o: constants.h
 connections.o: defs.h
 connections.o: id.h
@@ -300,6 +334,7 @@
 connections.o: adns.h
 connections.o: dnskey.h
 connections.o: whack.h
+connections.o: alg_info.h
 constants.o: constants.h
 constants.o: defs.h
 constants.o: log.h
@@ -373,6 +408,20 @@
 id.o: x509.h
 id.o: connections.h
 id.o: packet.h
+ike_alg.o: constants.h
+ike_alg.o: defs.h
+ike_alg.o: sha1.h
+ike_alg.o: md5.h
+ike_alg.o: crypto.h
+ike_alg.o: state.h
+ike_alg.o: packet.h
+ike_alg.o: kernel.h
+ike_alg.o: log.h
+ike_alg.o: whack.h
+ike_alg.o: spdb.h
+ike_alg.o: alg_info.h
+ike_alg.o: ike_alg.h
+ike_alg.o: db_ops.h
 ipsec_doi.o: constants.h
 ipsec_doi.o: defs.h
 ipsec_doi.o: state.h
@@ -397,6 +446,20 @@
 ipsec_doi.o: sha1.h
 ipsec_doi.o: md5.h
 ipsec_doi.o: crypto.h
+ipsec_doi.o: kernel_alg.h
+kernel_alg.o: constants.h
+kernel_alg.o: defs.h
+kernel_alg.o: id.h
+kernel_alg.o: connections.h
+kernel_alg.o: state.h
+kernel_alg.o: packet.h
+kernel_alg.o: spdb.h
+kernel_alg.o: kernel.h
+kernel_alg.o: kernel_alg.h
+kernel_alg.o: alg_info.h
+kernel_alg.o: log.h
+kernel_alg.o: whack.h
+kernel_alg.o: db_ops.h
 kernel.o: constants.h
 kernel.o: defs.h
 kernel.o: rnd.h
@@ -409,6 +472,8 @@
 kernel.o: log.h
 kernel.o: server.h
 kernel.o: whack.h
+kernel.o: alg_info.h
+kernel.o: kernel_alg.h
 kernel_comm.o: constants.h
 kernel_comm.o: defs.h
 kernel_comm.o: id.h
@@ -426,6 +491,8 @@
 kernel_comm.o: adns.h
 kernel_comm.o: dnskey.h
 kernel_comm.o: server.h
+kernel_comm.o: kernel_alg.h
+kernel_comm.o: ike_alg.h
 log.o: constants.h
 log.o: defs.h
 log.o: log.h
@@ -532,6 +599,10 @@
 spdb.o: sha1.h
 spdb.o: md5.h
 spdb.o: crypto.h
+spdb.o: alg_info.h
+spdb.o: kernel_alg.h
+spdb.o: ike_alg.h
+spdb.o: db_ops.h
 state.o: constants.h
 state.o: defs.h
 state.o: id.h
Index: freeswan/pluto/alg_info.c
diff -u /dev/null freeswan/pluto/alg_info.c:1.1.4.6
--- /dev/null	Fri Jul 12 16:03:46 2002
+++ freeswan/pluto/alg_info.c	Fri Jul  5 00:35:30 2002
@@ -0,0 +1,1034 @@
+/*
+ * Algorithm info parsing and creation functions
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: alg_info.c,v 1.1.4.6 2002/07/05 03:35:30 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.
+ */
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <freeswan.h>
+#include <pfkeyv2.h>
+
+#include "alg_info.h"
+#include "constants.h"
+#ifndef NO_PLUTO
+#include "defs.h"
+#include "log.h"
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h"
+#include "kernel_alg.h"
+#include "ike_alg.h"
+#else
+/*
+ *	macros/functions for compilation without pluto (eg: spi for manual conns)
+ */
+#include <assert.h>
+#define passert(x) assert(x)
+extern int debug;	/* eg: spi.c */
+#define DBG(cond, action)   { if (debug) { action ; } }
+#define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args);
+#define alloc_thing(thing, name) alloc_bytes(sizeof (thing), name)
+void * alloc_bytes(size_t size, const char *name) {
+	void *p=malloc(size);
+        if (p == NULL)
+		fprintf(stderr, "unable to malloc %lu bytes for %s",
+			(unsigned long) size, name);
+	memset(p, '\0', size);
+	return p;
+}
+#define pfreeany(ptr) free(ptr)
+#endif /* NO_PLUTO */
+
+/* sadb/ESP aa attrib converters */
+int
+alg_info_esp_aa2sadb(int auth)
+{
+	int sadb_aalg=0;
+	switch(auth) {
+		case AUTH_ALGORITHM_HMAC_MD5:
+		case AUTH_ALGORITHM_HMAC_SHA1:
+			sadb_aalg=auth+1;
+			break;
+		case AUTH_ALGORITHM_HMAC_SHA2_256:
+		case AUTH_ALGORITHM_HMAC_SHA2_384:
+		case AUTH_ALGORITHM_HMAC_SHA2_512:
+		case AUTH_ALGORITHM_HMAC_RIPEMD:
+			sadb_aalg=auth;
+			break;
+		default:
+			/* loose ... */
+			sadb_aalg=auth;
+	}
+	return sadb_aalg;
+}
+
+int /* __attribute__ ((unused)) */
+alg_info_esp_sadb2aa(int sadb_aalg)
+{
+	int auth=0;
+	switch(sadb_aalg) {
+		case SADB_AALG_MD5HMAC:
+		case SADB_AALG_SHA1HMAC:
+			auth=sadb_aalg-1;
+			break;
+			/* since they are the same ...  :)  */
+		case AUTH_ALGORITHM_HMAC_SHA2_256:
+		case AUTH_ALGORITHM_HMAC_SHA2_384:
+		case AUTH_ALGORITHM_HMAC_SHA2_512:
+		case AUTH_ALGORITHM_HMAC_RIPEMD:
+			auth=sadb_aalg;
+			break;
+		default:
+			/* loose ... */
+			auth=sadb_aalg;
+	}
+	return auth;
+}
+
+/*
+ * 	Search enum_name array with in prefixed uppercase
+ */
+static int
+enum_search_prefix (enum_names *ed, const char *prefix, const char *str, int strlen)
+{
+	char buf[64];
+	char *ptr;
+	int ret;
+	int len=sizeof(buf)-1;	/* reserve space for final \0 */
+	for (ptr=buf; *prefix; *ptr++=*prefix++, len--);
+	while (strlen--&&len--&&*str) *ptr++=toupper(*str++);
+	*ptr=0;
+	DBG(DBG_CRYPT, DBG_log(__FUNCTION__ "() "
+				"calling enum_search(%p, \"%s\")", ed, buf));
+	ret=enum_search(ed, buf);
+	return ret;
+}
+/*
+ * 	Search enum_name array with in prefixed and postfixed uppercase
+ */
+static int
+enum_search_ppfix (enum_names *ed, const char *prefix, const char *postfix, const char *str, int strlen)
+{
+	char buf[64];
+	char *ptr;
+	int ret;
+	int len=sizeof(buf)-1;	/* reserve space for final \0 */
+	for (ptr=buf; *prefix; *ptr++=*prefix++, len--);
+	while (strlen--&&len--&&*str) *ptr++=toupper(*str++);
+	while (len--&&*postfix) *ptr++=*postfix++;
+	*ptr=0;
+	DBG(DBG_CRYPT, DBG_log(__FUNCTION__ "() "
+				"calling enum_search(%p, \"%s\")", ed, buf));
+	ret=enum_search(ed, buf);
+	return ret;
+}
+/*
+ * 	Search esp_transformid_names for a match, eg:
+ * 		"3des" <=> "ESP_3DES"
+ */
+#define ESP_MAGIC_ID 0x00ffff01
+static int
+ealg_getbyname_esp(const char *const str, int len)
+{
+	int ret=-1;
+	if (!str||!*str)
+		goto out;
+	/* leave special case for eg:  "id248" string */
+	if (strcmp("id", str)==0)
+		return ESP_MAGIC_ID;
+	ret=enum_search_prefix(&esp_transformid_names, "ESP_", str, len);
+out:
+	return ret;
+}
+/*
+ * 	Search auth_alg_names for a match, eg:
+ * 		"md5" <=> "AUTH_ALGORITHM_HMAC_MD5"
+ */
+static int
+aalg_getbyname_esp(const char *const str, int len)
+{
+	int ret=-1;
+	unsigned num;
+	if (!str||!*str)
+		goto out;
+	ret=enum_search_prefix(&auth_alg_names,"AUTH_ALGORITHM_HMAC_",str,len);
+	if (ret>=0) goto out;
+	ret=enum_search_prefix(&auth_alg_names,"AUTH_ALGORITHM_",str,len);
+	if (ret>=0) goto out;
+	sscanf(str, "id%d%n", &ret, &num);
+	if (ret >=0 && num!=strlen(str))
+		ret=-1;
+out:
+	return ret;
+}
+static int
+modp_getbyname_esp(const char *const str, int len)
+{
+	int ret=-1;
+	if (!str||!*str)
+		goto out;
+	ret=enum_search_prefix(&oakley_group_names,"OAKLEY_GROUP_",str,len);
+	if (ret>=0) goto out;
+	ret=enum_search_ppfix(&oakley_group_names, "OAKLEY_GROUP_", " (extension)", str, len);
+out:
+	return ret;
+}
+void 
+alg_info_free(struct alg_info *alg_info) {
+	pfreeany(alg_info);
+}
+/*	
+ *	Raw add routine: only checks for no duplicates		
+ */
+static void
+__alg_info_esp_add (struct alg_info_esp *alg_info, int ealg_id, unsigned ek_bits, int aalg_id, unsigned ak_bits)
+{
+	struct esp_info *esp_info=alg_info->esp;
+	unsigned cnt=alg_info->alg_info_cnt, i;
+	/* 	check for overflows 	*/
+	passert(cnt < elemsof(alg_info->esp));
+	/*	dont add duplicates	*/
+	for (i=0;i<cnt;i++)
+		if (	esp_info[i].esp_ealg_id==ealg_id &&
+			(!ek_bits || esp_info[i].esp_ealg_keylen==ek_bits) &&
+			esp_info[i].esp_aalg_id==aalg_id &&
+			(!ak_bits || esp_info[i].esp_aalg_keylen==ak_bits))
+			return;
+	esp_info[cnt].esp_ealg_id=ealg_id;
+	esp_info[cnt].esp_ealg_keylen=ek_bits;
+	esp_info[cnt].esp_aalg_id=aalg_id;
+	esp_info[cnt].esp_aalg_keylen=ak_bits;
+	/* sadb values */
+	esp_info[cnt].encryptalg=ealg_id;
+	esp_info[cnt].authalg=alg_info_esp_aa2sadb(aalg_id);
+	alg_info->alg_info_cnt++;
+	DBG(DBG_CRYPT, DBG_log(__FUNCTION__ "() "
+				"ealg=%d aalg=%d cnt=%d",
+				ealg_id, aalg_id, alg_info->alg_info_cnt));
+}
+
+/*	
+ *	Add ESP alg info _with_ logic (policy):
+ */
+static void
+alg_info_esp_add (struct alg_info *alg_info, int ealg_id, int ek_bits, int aalg_id, int ak_bits)
+{
+	/*	Policy: default to 3DES */
+	if (ealg_id==0)
+		ealg_id=ESP_3DES;
+	if (ealg_id>0) {
+		if (aalg_id>0)
+			__alg_info_esp_add((struct alg_info_esp *)alg_info,
+					ealg_id, ek_bits,
+					aalg_id, ak_bits);
+		else {
+			/*	Policy: default to MD5 and SHA1 */
+			__alg_info_esp_add((struct alg_info_esp *)alg_info,
+					ealg_id, ek_bits, \
+					AUTH_ALGORITHM_HMAC_MD5, ak_bits);
+			__alg_info_esp_add((struct alg_info_esp *)alg_info,
+					ealg_id, ek_bits, \
+					AUTH_ALGORITHM_HMAC_SHA1, ak_bits);
+		}
+	}
+}
+
+#ifndef NO_PLUTO
+/**************************************
+ *
+ *	IKE alg
+ *
+ *************************************/
+/*
+ * 	Search oakley_enc_names for a match, eg:
+ * 		"3des_cbc" <=> "OAKLEY_3DES_CBC"
+ */
+static int
+ealg_getbyname_ike(const char *const str, int len)
+{
+	int ret=-1;
+	if (!str||!*str)
+		goto out;
+	ret=enum_search_prefix(&oakley_enc_names,"OAKLEY_",str,len);
+	if (ret>=0) goto out;
+	ret=enum_search_ppfix(&oakley_enc_names, "OAKLEY_", "_CBC", str, len);
+out:
+	return ret;
+}
+/*
+ * 	Search  oakley_hash_names for a match, eg:
+ * 		"md5" <=> "OAKLEY_MD5"
+ */
+static int
+aalg_getbyname_ike(const char *const str, int len)
+{
+	int ret=-1;
+	unsigned num;
+	if (!str||!*str)
+		goto out;
+	ret=enum_search_prefix(&oakley_hash_names,"OAKLEY_",str,len);
+	if (ret>=0) goto out;
+	sscanf(str, "id%d%n", &ret, &num);
+	if (ret >=0 && num!=strlen(str))
+		ret=-1;
+out:
+	return ret;
+}
+/*
+ * 	Search oakley_group_names for a match, eg:
+ * 		"modp1024" <=> "OAKLEY_GROUP_MODP1024"
+ */
+static int
+modp_getbyname_ike(const char *const str, int len)
+{
+	int ret=-1;
+	if (!str||!*str)
+		goto out;
+	ret=enum_search_prefix(&oakley_group_names,"OAKLEY_GROUP_",str,len);
+	if (ret>=0) goto out;
+	ret=enum_search_ppfix(&oakley_group_names, "OAKLEY_GROUP_", " (extension)", str, len);
+out:
+	return ret;
+}
+static void
+__alg_info_ike_add (struct alg_info_ike *alg_info, int ealg_id, unsigned ek_bits, int aalg_id, unsigned ak_bits, int modp_id)
+{
+	struct ike_info *ike_info=alg_info->ike;
+	unsigned cnt=alg_info->alg_info_cnt, i;
+	/* 	check for overflows 	*/
+	passert(cnt < elemsof(alg_info->ike));
+	/*	dont add duplicates	*/
+	for (i=0;i<cnt;i++)
+		if (	ike_info[i].ike_ealg==ealg_id &&
+			(!ek_bits || ike_info[i].ike_eklen==ek_bits) &&
+			ike_info[i].ike_halg==aalg_id &&
+			(!ak_bits || ike_info[i].ike_hklen==ak_bits) &&
+			ike_info[i].ike_modp==modp_id
+		   )
+			return;
+	ike_info[cnt].ike_ealg=ealg_id;
+	ike_info[cnt].ike_eklen=ek_bits;
+	ike_info[cnt].ike_halg=aalg_id;
+	ike_info[cnt].ike_hklen=ak_bits;
+	ike_info[cnt].ike_modp=modp_id;
+	alg_info->alg_info_cnt++;
+	DBG(DBG_CRYPT, DBG_log(__FUNCTION__ "() "
+				"ealg=%d aalg=%d modp_id=%d, cnt=%d",
+				ealg_id, aalg_id, modp_id,
+				alg_info->alg_info_cnt));
+}
+
+/*	
+ * 	Proposals will be built by looping over default_ike_groups array and
+ * 	merging alg_info (ike_info) contents
+ */
+
+static int default_ike_groups[] = { 
+	OAKLEY_GROUP_MODP1536,
+	OAKLEY_GROUP_MODP1024
+};
+
+/*	
+ *	Add IKE alg info _with_ logic (policy):
+ */
+static void
+alg_info_ike_add (struct alg_info *alg_info, int ealg_id, int ek_bits, int aalg_id, int ak_bits, int modp_id)
+{
+	int i=0, n_groups;
+	n_groups=elemsof(default_ike_groups);
+	/* if specified modp_id avoid loop over default_ike_groups */
+	if (modp_id) {
+		n_groups=0;
+		goto in_loop;
+	}
+	
+	for (;n_groups--;i++) {
+		modp_id=default_ike_groups[i];
+in_loop:
+		/*	Policy: default to 3DES */
+		if (ealg_id==0)
+			ealg_id=OAKLEY_3DES_CBC;
+		if (ealg_id>0) {
+			if (aalg_id>0)
+				__alg_info_ike_add((struct alg_info_ike *)alg_info,
+						ealg_id, ek_bits,
+						aalg_id, ak_bits,
+						modp_id);
+			else {
+				/*	Policy: default to MD5 and SHA */
+				__alg_info_ike_add((struct alg_info_ike *)alg_info,
+						ealg_id, ek_bits, \
+						OAKLEY_MD5, ak_bits, modp_id);
+				__alg_info_ike_add((struct alg_info_ike *)alg_info,
+						ealg_id, ek_bits, \
+						OAKLEY_SHA, ak_bits, modp_id);
+			}
+		}
+	}
+}
+#endif /* NO_PLUTO */
+
+/*	
+ *	Creates a new alg_info by parsing passed string		
+ */
+enum parser_state_esp {
+	ST_INI,
+	ST_EA,		/* encrypt algo   */
+	ST_EA_END,	
+	ST_EK,		/* enc. key length */
+	ST_EK_END,
+	ST_AA,		/* auth algo */
+	ST_AA_END,
+	ST_AK,		/* auth. key length */
+	ST_AK_END,
+	ST_MODP,	/* modp spec */
+	ST_FLAG_STRICT,
+	ST_END,
+	ST_EOF,
+	ST_ERR
+};
+static const char *parser_state_esp_names[] = {
+	"ST_INI",
+	"ST_EA",
+	"ST_EA_END",	
+	"ST_EK",
+	"ST_EK_END",
+	"ST_AA",
+	"ST_AA_END",
+	"ST_AK",
+	"ST_AK_END",
+	"ST_MOPD",
+	"ST_FLAG_STRICT",
+	"ST_END",
+	"ST_EOF",
+	"ST_ERR"
+};
+static const char *parser_state_name_esp(enum parser_state_esp state) {
+	return parser_state_esp_names[state];
+}
+/* XXX:jjo to implement different parser for ESP and IKE */
+struct parser_context {
+	unsigned state, old_state;
+	unsigned protoid;
+	char ealg_buf[16];
+	char aalg_buf[16];
+	char modp_buf[16];
+	int (*ealg_getbyname)(const char *const str, int len);
+	int (*aalg_getbyname)(const char *const str, int len);
+	int (*modp_getbyname)(const char *const str, int len);
+	char *ealg_str;
+	char *aalg_str;
+	char *modp_str;
+	int eklen;
+	int aklen;
+	int ch;
+	const char *err;
+};
+static inline void parser_set_state(struct parser_context *p_ctx, enum parser_state_esp state) {
+	if (state!=p_ctx->state) {
+		p_ctx->old_state=p_ctx->state;
+		p_ctx->state=state;
+	}
+	
+}
+static int 
+parser_machine(struct parser_context *p_ctx)
+{
+	int ch=p_ctx->ch;
+	/* special 'absolute' cases */
+	p_ctx->err="No error.";
+
+	/* chars that end algo strings */
+	switch(ch){
+		case 0:		/* end-of-string */
+		case '!':	/* flag as strict algo list */
+		case ',':	/* algo string separator */
+			switch(p_ctx->state) {
+				case ST_EA:
+				case ST_EK:
+				case ST_AA:
+				case ST_AK: 
+				case ST_MODP:
+				case ST_FLAG_STRICT:
+					{
+					enum parser_state_esp next_state=0;
+					switch(ch) {
+						case 0:   next_state=ST_EOF;break;
+						case ',': next_state=ST_END;break;
+						case '!': next_state=ST_FLAG_STRICT;break;
+					}
+					/* ch? parser_set_state(p_ctx, ST_END) : parser_set_state(p_ctx, ST_EOF) ; */
+					parser_set_state(p_ctx, next_state);
+					goto out;
+				}
+				default:
+					p_ctx->err="String ended with invalid char";
+					goto err;
+			}
+	}
+re_eval:
+	switch(p_ctx->state) {
+		case ST_INI:
+			if (isspace(ch))
+				break;
+			if (isalnum(ch)) {
+				*(p_ctx->ealg_str++)=ch;
+				parser_set_state(p_ctx, ST_EA);
+				break;
+			}
+			p_ctx->err="No alphanum. char initially found";
+			goto err;
+		case ST_EA:
+			if (isalpha(ch) || ch == '_') {
+				*(p_ctx->ealg_str++)=ch;
+				break;
+			}
+			if (isdigit(ch)) {
+				/* bravely switch to enc keylen */
+				*(p_ctx->ealg_str)=0;
+				parser_set_state(p_ctx, ST_EK);
+				goto re_eval;
+			}
+			if (ch=='-') {
+				*(p_ctx->ealg_str)=0;
+				parser_set_state(p_ctx, ST_EA_END);
+				break;
+			}
+			p_ctx->err="No valid char found after enc alg string";
+			goto err;
+		case ST_EA_END:
+			if (isdigit(ch)) {
+				/* bravely switch to enc keylen */
+				parser_set_state(p_ctx, ST_EK);
+				goto re_eval;
+			}
+			if (isalpha(ch)) {
+				parser_set_state(p_ctx, ST_AA);
+				goto re_eval;
+			}
+			p_ctx->err="No alphanum char found after enc alg separator";
+			goto err;
+		case ST_EK:
+			if (ch=='-') {
+				parser_set_state(p_ctx, ST_EK_END);
+				break;
+			}
+			if (isdigit(ch)) {
+				p_ctx->eklen=p_ctx->eklen*10+ch-'0';
+				break;
+			}
+			p_ctx->err="Non digit or valid separator found while reading enc keylen";
+			goto err;
+		case ST_EK_END:
+			if (isalpha(ch)) {
+				parser_set_state(p_ctx, ST_AA);
+				goto re_eval;
+			}
+			p_ctx->err="Non alpha char found after enc keylen end separator";
+			goto err;
+		case ST_AA:
+			if (ch=='-') {
+				*(p_ctx->aalg_str++)=0;
+				parser_set_state(p_ctx, ST_AA_END);
+				break;
+			}
+			if (isalnum(ch) || ch=='_') {
+				*(p_ctx->aalg_str++)=ch;
+				break;
+			}
+			p_ctx->err="Non alphanum or valid separator found in auth string";
+			goto err;
+		case ST_AA_END:
+			if (isdigit(ch)) {
+				parser_set_state(p_ctx, ST_AK);
+				goto re_eval;
+			}
+			/* Only allow modpXXXX string if we have
+			 * a modp_getbyname method
+			 */
+			if ((p_ctx->modp_getbyname) && isalpha(ch)) {
+				parser_set_state(p_ctx, ST_MODP);
+				goto re_eval;
+			}
+			p_ctx->err="Non initial digit found for auth keylen";
+			goto err;
+		case ST_AK:
+			if (ch=='-') {
+				parser_set_state(p_ctx, ST_AK_END);
+				break;
+			}
+			if (isdigit(ch)) {
+				p_ctx->aklen=p_ctx->aklen*10+ch-'0';
+				break;
+			}
+			p_ctx->err="Non digit found for auth keylen";
+			goto err;
+		case ST_AK_END:
+			/* Only allow modpXXXX string if we have
+			 * a modp_getbyname method
+			 */
+			if ((p_ctx->modp_getbyname) && isalpha(ch)) {
+				parser_set_state(p_ctx, ST_MODP);
+				goto re_eval;
+			}
+			p_ctx->err="Non alpha char found after auth keylen";
+			goto err;
+		case ST_MODP:
+			if (isalnum(ch)) {
+				*(p_ctx->modp_str++)=ch;
+				break;
+			}
+			p_ctx->err="Non alphanum char found after in modp string";
+			goto err;
+		case ST_FLAG_STRICT:
+			if (ch == 0) {
+				parser_set_state(p_ctx, ST_END);
+			}
+			p_ctx->err="Flags character(s) must be at end of whole string";
+			goto err;
+
+		/* XXX */
+		case ST_END:
+		case ST_EOF:
+		case ST_ERR:
+		/* XXX */
+	}
+out:
+	return p_ctx->state;
+err:
+	parser_set_state(p_ctx, ST_ERR);
+	return ST_ERR;
+}
+/*	
+ *	Must be called for each "new" char, with new
+ *	character in ctx.ch
+ */
+static void
+parser_init(struct parser_context *p_ctx, unsigned protoid)
+{
+	memset(p_ctx, 0, sizeof (*p_ctx));
+	p_ctx->protoid=protoid; /* XXX: jjo */
+	p_ctx->protoid=PROTO_IPSEC_ESP;
+	p_ctx->ealg_str=p_ctx->ealg_buf;
+	p_ctx->aalg_str=p_ctx->aalg_buf;
+	p_ctx->modp_str=p_ctx->modp_buf;
+	p_ctx->state=ST_INI;
+	switch(protoid) {
+#ifndef NO_PLUTO
+		case PROTO_ISAKMP:
+			p_ctx->ealg_getbyname=ealg_getbyname_ike;
+			p_ctx->aalg_getbyname=aalg_getbyname_ike;
+			p_ctx->modp_getbyname=modp_getbyname_ike;
+			break;
+#endif
+		case PROTO_IPSEC_ESP:
+			p_ctx->ealg_getbyname=ealg_getbyname_esp;
+			p_ctx->aalg_getbyname=aalg_getbyname_esp;
+			break;
+	}
+}
+static int
+parser_alg_info_add(struct parser_context *p_ctx, struct alg_info *alg_info)
+{
+	int ealg_id, aalg_id;
+	int modp_id = 0;
+#ifndef NO_PLUTO
+	const struct oakley_group_desc *gd;
+#endif
+	ealg_id=aalg_id=0;
+	if (*p_ctx->ealg_buf) {
+		ealg_id=p_ctx->ealg_getbyname(p_ctx->ealg_buf, strlen(p_ctx->ealg_buf));
+		if (ealg_id==ESP_MAGIC_ID) {
+			ealg_id=p_ctx->eklen;
+			p_ctx->eklen=0;
+		}
+		if (ealg_id<0) {
+			p_ctx->err="enc_alg not found";
+			goto out;
+		}
+		DBG(DBG_CRYPT, DBG_log(__FUNCTION__ "() "
+				"ealg_getbyname(\"%s\")=%d",
+				p_ctx->ealg_buf,
+				ealg_id));
+	}
+	if (*p_ctx->aalg_buf) {
+		aalg_id=p_ctx->aalg_getbyname(p_ctx->aalg_buf, strlen(p_ctx->aalg_buf));
+		if (aalg_id<0) {
+			p_ctx->err="hash_alg not found";
+			goto out;
+		}
+		DBG(DBG_CRYPT, DBG_log(__FUNCTION__ "() "
+				"aalg_getbyname(\"%s\")=%d",
+				p_ctx->aalg_buf,
+				aalg_id));
+	}
+	if (p_ctx->modp_getbyname && *p_ctx->modp_buf) {
+		modp_id=p_ctx->modp_getbyname(p_ctx->modp_buf, strlen(p_ctx->modp_buf));
+		if (modp_id<0) {
+			p_ctx->err="modp group not found";
+			goto out;
+		}
+		DBG(DBG_CRYPT, DBG_log(__FUNCTION__ "() "
+				"modp_getbyname(\"%s\")=%d",
+				p_ctx->modp_buf,
+				modp_id));
+	}
+	switch(alg_info->alg_info_protoid) {
+		case PROTO_IPSEC_ESP:
+			alg_info_esp_add(alg_info,
+					ealg_id, p_ctx->eklen,
+					aalg_id, p_ctx->aklen);
+			break;
+#ifndef NO_PLUTO
+		case PROTO_ISAKMP:
+			if (modp_id && !(gd=lookup_group(modp_id))) {
+				p_ctx->err="found modp group id, but not supported";
+				goto out;
+			}
+			alg_info_ike_add(alg_info,
+					ealg_id, p_ctx->eklen,
+					aalg_id, p_ctx->aklen,
+					modp_id);
+			break;
+#endif
+		default:
+			goto out;
+	}
+	return 0;
+out:
+	return -1;
+}
+static int
+alg_info_parse_str (struct alg_info *alg_info, const char *alg_str, const char **err_p)
+{
+	struct parser_context ctx;
+	int ret;
+	const char *ptr;
+	static char err_buf[256];
+	*err_buf=0;
+	parser_init(&ctx, alg_info->alg_info_protoid);
+	if (err_p) *err_p=NULL;
+	/* use default if nul esp string */
+	if (!*alg_str) {
+		switch (alg_info->alg_info_protoid) {
+#ifndef NO_PLUTO
+			case PROTO_ISAKMP:
+				alg_info_ike_add(alg_info, 0, 0, 0, 0, 0);
+				return 0;
+#endif
+			case PROTO_IPSEC_ESP:
+				alg_info_esp_add(alg_info, 0, 0, 0, 0);
+				return 0;
+			default:
+				/* IMPOSSIBLE */
+				passert(alg_info->alg_info_protoid);
+		}
+	}
+
+	for(ret=0,ptr=alg_str;ret<ST_EOF;) {
+		ctx.ch=*ptr++;
+		ret= parser_machine(&ctx);
+		switch(ret) {
+			case ST_FLAG_STRICT:
+				alg_info->alg_info_flags |= ALG_INFO_F_STRICT;
+				break;
+			case ST_END:
+			case ST_EOF:
+				DBG(DBG_CRYPT, DBG_log(__FUNCTION__ "() "
+				"ealg_buf=%s aalg_buf=%s"
+				"eklen=%d  aklen=%d",
+				ctx.ealg_buf, ctx.aalg_buf,
+				ctx.eklen, ctx.aklen));
+				if (parser_alg_info_add(&ctx, alg_info)<0) {
+					snprintf(err_buf, sizeof(err_buf),
+					"%s, enc_alg=\"%s\", auth_alg=\"%s\", "
+					"modp=\"%s\"",
+					ctx.err,
+					ctx.ealg_buf,
+					ctx.aalg_buf,
+					ctx.modp_buf);
+					goto err;
+				}
+				/* zero out for next run (ST_END) */
+				parser_init(&ctx, alg_info->alg_info_protoid);
+				break;
+			case ST_ERR:
+				snprintf(err_buf, sizeof(err_buf),
+					"%s, "
+					"just after \"%.*s\""
+					" (old_state=%s)",
+					ctx.err,
+					ptr-alg_str-1, alg_str ,
+					parser_state_name_esp(ctx.old_state) );
+
+				goto err;
+			default:
+				if (!ctx.ch) break;
+		}
+	}
+	return 0;
+err:
+	if (err_p) {
+		*err_p=err_buf;
+	}
+	return -1;
+}
+struct alg_info_esp *
+alg_info_esp_create_from_str (const char *alg_str, const char **err_p)
+{
+	struct alg_info_esp *alg_info_esp;
+	char esp_buf[256];
+	static char err_buf[256];
+	char *pfs_name;
+	int ret =0;
+	/*
+	 * 	alg_info storage should be sized dynamically
+	 * 	but this may require 2passes to know
+	 * 	transform count in advance.
+	 */
+	alg_info_esp=alloc_thing (struct alg_info_esp, "alg_info_esp");
+	if (!alg_info_esp) goto out;
+	pfs_name=index (alg_str, ';');
+	if (pfs_name) {
+		memcpy(esp_buf, alg_str, pfs_name-alg_str);
+		esp_buf[pfs_name-alg_str] = 0;
+		alg_str=esp_buf;
+		pfs_name++;
+		/* if pfs strings AND first char is not '0' */
+		if (*pfs_name && pfs_name[0]!='0') {
+			ret=modp_getbyname_esp(pfs_name, strlen(pfs_name));
+			if (ret<0) {
+				/* Bomb if pfsgroup not found */
+				DBG(DBG_CRYPT, DBG_log(__FUNCTION__ "(): "
+					"pfsgroup \"%s\" not found",
+					pfs_name));
+				if (*err_p) {
+					snprintf(err_buf, sizeof(err_buf),
+						"pfsgroup \"%s\" not found",
+						pfs_name);
+					*err_p=err_buf;
+				}
+				goto out;
+			}
+			alg_info_esp->esp_pfsgroup=ret;
+		}
+	}
+	alg_info_esp->alg_info_protoid=PROTO_IPSEC_ESP;
+	ret=alg_info_parse_str((struct alg_info *)alg_info_esp, alg_str, err_p) ;
+out:
+	if (ret<0)
+	{
+		pfreeany(alg_info_esp);
+		alg_info_esp=NULL;
+	}
+	return alg_info_esp;
+
+}
+#ifndef NO_PLUTO
+struct alg_info_ike *
+alg_info_ike_create_from_str (const char *alg_str, const char **err_p)
+{
+	struct alg_info_ike *alg_info_ike;
+	/*
+	 * 	alg_info storage should be sized dynamically
+	 * 	but this may require 2passes to know
+	 * 	transform count in advance.
+	 */
+	alg_info_ike=alloc_thing (struct alg_info_ike, "alg_info_ike");
+	if (!alg_info_ike) goto out;
+	alg_info_ike->alg_info_protoid=PROTO_ISAKMP;
+	if (alg_info_parse_str((struct alg_info *)alg_info_ike,
+					alg_str, err_p) < 0)
+	{
+		pfreeany(alg_info_ike);
+		alg_info_ike=NULL;
+	}
+out:
+	return alg_info_ike;
+}
+#endif
+/*
+ * 	alg_info struct can be shared by
+ * 	several connections instances,
+ * 	handle free() with ref_cnts
+ */
+void 
+alg_info_addref(struct alg_info *alg_info)
+{
+	if (alg_info != NULL) {
+		alg_info->ref_cnt++;
+		DBG(DBG_CRYPT, DBG_log(__FUNCTION__ "() "
+				"alg_info->ref_cnt=%d", alg_info->ref_cnt));
+	}
+}
+void
+alg_info_delref(struct alg_info **alg_info_p)
+{
+	struct alg_info *alg_info=*alg_info_p;
+	if (alg_info != NULL) {
+		passert(alg_info->ref_cnt != 0);
+		alg_info->ref_cnt--;
+		DBG(DBG_CRYPT, DBG_log(__FUNCTION__ "() "
+				"alg_info->ref_cnt=%d", alg_info->ref_cnt));
+		if (alg_info->ref_cnt==0) {
+			DBG(DBG_CRYPT, DBG_log(__FUNCTION__ "() "
+				"freeing alg_info"));
+			alg_info_free(alg_info);
+		}
+		*alg_info_p=NULL;
+	}
+}
+
+/*	snprint already parsed transform list (alg_info)	*/
+int
+alg_info_snprint(char *buf, int buflen, struct alg_info *alg_info)
+{
+	char *ptr=buf;
+	int np=0;
+	struct esp_info *esp_info;
+#ifndef NO_PLUTO
+	struct ike_info *ike_info;
+#endif
+	int cnt;
+	/* ptr+=sprintf(buf, "{ealg[eklen],aalg[aklen]} = "); */
+	ptr=buf;
+	switch(alg_info->alg_info_protoid) {
+		case PROTO_IPSEC_ESP: 
+		{
+			struct alg_info_esp *alg_info_esp=(struct alg_info_esp *)alg_info;
+			ALG_INFO_ESP_FOREACH(alg_info_esp, esp_info, cnt) {
+				np=snprintf(ptr, buflen, "%d_%03d-%d, "
+						, esp_info->esp_ealg_id
+						, esp_info->esp_ealg_keylen
+						, esp_info->esp_aalg_id);
+				ptr+=np;
+				buflen-=np;
+			}
+			if (alg_info_esp->esp_pfsgroup) {
+				np=snprintf(ptr, buflen, "; pfsgroup=%d; "
+					, alg_info_esp->esp_pfsgroup);
+				ptr+=np;
+				buflen-=np;
+			}
+			break;
+	        }
+#ifndef NO_PLUTO
+		case PROTO_ISAKMP:
+			ALG_INFO_IKE_FOREACH((struct alg_info_ike *)alg_info, ike_info, cnt) {
+				np=snprintf(ptr, buflen, "%d_%03d-%d-%d, ",
+						ike_info->ike_ealg,
+						ike_info->ike_eklen,
+						ike_info->ike_halg,
+						ike_info->ike_modp);
+				ptr+=np;
+				buflen-=np;
+			}
+			break;
+#endif
+		default:
+			np=snprintf(buf, buflen, "INVALID protoid=%d\n",
+					alg_info->alg_info_protoid);
+			goto out;
+	}
+	ptr+=sprintf(ptr, "flags=%s",
+			alg_info->alg_info_flags&ALG_INFO_F_STRICT?
+			"strict":"-strict");
+out:
+	return ptr-buf;
+}
+
+#ifndef NO_PLUTO
+int
+alg_info_snprint_esp(char *buf, int buflen, struct alg_info_esp *alg_info)
+{
+	char *ptr=buf;
+	int ret;
+	struct esp_info *esp_info;
+	int cnt;
+	int eklen, aklen;
+	/* ptr+=sprintf(buf, "{ealg[eklen],aalg[aklen]} = "); */
+	ptr=buf;
+	*ptr=0;
+	ALG_INFO_ESP_FOREACH(alg_info, esp_info, cnt) {
+		if (kernel_alg_esp_enc_ok(esp_info->esp_ealg_id, 0, NULL) &&
+			(kernel_alg_esp_auth_ok(esp_info->esp_aalg_id, NULL))) {
+		eklen=esp_info->esp_ealg_keylen;
+		if (!eklen) 
+			eklen=kernel_alg_esp_enc_keylen(esp_info->esp_ealg_id)*BITS_PER_BYTE;
+		aklen=esp_info->esp_aalg_keylen;
+		if (!aklen) 
+			aklen=kernel_alg_esp_auth_keylen(esp_info->esp_aalg_id)*BITS_PER_BYTE;
+		ret=snprintf(ptr, buflen, "%d_%03d-%d_%03d, ",
+				esp_info->esp_ealg_id,
+				eklen,
+				esp_info->esp_aalg_id,
+				aklen);
+		ptr+=ret;
+		buflen-=ret;
+		}
+	}
+	return buflen;
+}
+
+int
+alg_info_snprint_ike(char *buf, int buflen, struct alg_info_ike *alg_info)
+{
+	char *ptr=buf;
+	int ret;
+	struct ike_info *ike_info;
+	int cnt;
+	int eklen, aklen;
+	struct encrypt_desc *enc_desc;
+	struct hash_desc *hash_desc;
+	/* ptr+=sprintf(buf, "{ealg[eklen],aalg[aklen]} = "); */
+	ptr=buf;
+	*ptr=0;
+	ALG_INFO_IKE_FOREACH(alg_info, ike_info, cnt) {
+		if (ike_alg_enc_present(ike_info->ike_ealg) 
+			&& (ike_alg_hash_present(ike_info->ike_halg)) 
+			&& (lookup_group(ike_info->ike_modp))
+			) {
+		enc_desc=ike_alg_get_encrypter(ike_info->ike_ealg);
+		passert(enc_desc != NULL);
+		hash_desc=ike_alg_get_hasher(ike_info->ike_halg);
+		passert(hash_desc != NULL);
+
+		eklen=ike_info->ike_eklen;
+		if (!eklen) 
+			eklen=enc_desc->keydeflen;
+		aklen=ike_info->ike_hklen;
+		if (!aklen) 
+			aklen=hash_desc->hash_digest_size * BITS_PER_BYTE;
+		ret=snprintf(ptr, buflen, "%d_%03d-%d_%03d-%d, ",
+				ike_info->ike_ealg,
+				eklen,
+				ike_info->ike_halg,
+				aklen,
+				ike_info->ike_modp);
+		ptr+=ret;
+		buflen-=ret;
+		}
+	}
+	return buflen;
+}
+#endif /* NO_PLUTO */
Index: freeswan/pluto/alg_info.h
diff -u /dev/null freeswan/pluto/alg_info.h:1.1.4.2
--- /dev/null	Fri Jul 12 16:03:46 2002
+++ freeswan/pluto/alg_info.h	Thu May 30 00:26:08 2002
@@ -0,0 +1,74 @@
+/*
+ * Algorithm info parsing and creation functions
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: alg_info.h,v 1.1.4.2 2002/05/30 03:26:08 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.
+ */
+#ifndef ALG_INFO_H
+#define ALG_INFO_H
+struct esp_info {
+	u_int8_t transid;	/* ESP transform */
+	u_int16_t auth;		/* AUTH */
+	size_t enckeylen;	/* keylength for ESP transform */
+	size_t authkeylen;	/* keylength for AUTH */
+	u_int8_t encryptalg;	/* normally  encryptalg=transid */
+	u_int8_t authalg;	/* normally  authalg=auth+1 */
+};
+struct ike_info {
+	u_int16_t ike_ealg;	/* high 16 bit nums for reserved */
+	u_int8_t ike_halg;
+	size_t ike_eklen;
+	size_t ike_hklen;
+	u_int16_t ike_modp;
+};
+#define ALG_INFO_COMMON \
+	int alg_info_cnt;		\
+	int ref_cnt;			\
+	unsigned alg_info_flags;	\
+	unsigned alg_info_protoid
+struct alg_info {
+	ALG_INFO_COMMON;
+};
+struct alg_info_esp {
+	ALG_INFO_COMMON;
+	struct esp_info esp[64];
+	int esp_pfsgroup;
+};
+struct alg_info_ike {
+	ALG_INFO_COMMON;
+	struct ike_info ike[64];
+};
+#define esp_ealg_id transid
+#define esp_aalg_id auth
+#define esp_ealg_keylen enckeylen	/* bits */
+#define esp_aalg_keylen authkeylen	/* bits */
+
+/*	alg_info_flags bits */
+#define ALG_INFO_F_STRICT	0x01
+
+int alg_info_esp_aa2sadb(int auth);
+int alg_info_esp_sadb2aa(int sadb_aalg);
+void alg_info_free(struct alg_info *alg_info);
+void alg_info_addref(struct alg_info *alg_info);
+void alg_info_delref(struct alg_info **alg_info);
+struct alg_info_esp * alg_info_esp_create_from_str (const char *alg_str, const char **err_p);
+struct alg_info_ike * alg_info_ike_create_from_str (const char *alg_str, const char **err_p);
+int alg_info_parse(const char *str);
+int alg_info_snprint(char *buf, int buflen, struct alg_info *alg_info);
+int alg_info_snprint_esp(char *buf, int buflen, struct alg_info_esp *alg_info);
+int alg_info_snprint_ike(char *buf, int buflen, struct alg_info_ike *alg_info);
+#define ALG_INFO_ESP_FOREACH(ai, ai_esp, i) \
+	for (i=(ai)->alg_info_cnt,ai_esp=(ai)->esp; i--; ai_esp++) 
+#define ALG_INFO_IKE_FOREACH(ai, ai_ike, i) \
+	for (i=(ai)->alg_info_cnt,ai_ike=(ai)->ike; i--; ai_ike++) 
+#endif /* ALG_INFO_H */
Index: freeswan/pluto/alg_info_test.c
diff -u /dev/null freeswan/pluto/alg_info_test.c:1.1.4.2
--- /dev/null	Fri Jul 12 16:03:46 2002
+++ freeswan/pluto/alg_info_test.c	Thu May 30 00:26:08 2002
@@ -0,0 +1,138 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <freeswan.h>
+#define NO_PLUTO
+#include "alg_info.h"
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#define STR_EXAMPLE_ESP "3des, aes128-sha1"
+#define STR_EXAMPLE_IKE "3des, aes128-sha, aes128-sha2_256-modp2048"
+static void setup_debugging(void) {
+	log_to_stderr=TRUE;
+	log_to_syslog=FALSE;
+	init_log();
+	cur_debugging=~0;
+}
+static int doit(unsigned protoid, const char *str)
+{
+	struct alg_info *ai;
+	enum_names *enames, *anames, *gnames;
+	const char *err;
+	int i;
+	switch (protoid) {
+		case PROTO_IPSEC_ESP: {
+			struct alg_info_esp *ai_esp;
+			struct esp_info *esp_info;
+			enames=&esp_transformid_names;
+			anames=&auth_alg_names;
+			gnames=NULL;
+			ai_esp=alg_info_esp_create_from_str(str, &err);
+			ai = (struct alg_info *) ai_esp;
+			if (!ai) goto err;
+			alg_info_addref(ai);
+			ALG_INFO_ESP_FOREACH(ai_esp, esp_info, i) {
+				printf("(%d = \"%s\" [%d], ", 
+					esp_info->esp_ealg_id, 
+					enum_name(enames, esp_info->esp_ealg_id),
+					esp_info->esp_ealg_keylen);
+				printf("%d = \"%s\" [%d])\n", 
+					esp_info->esp_aalg_id,
+					enum_name(anames, esp_info->esp_aalg_id),
+					esp_info->esp_aalg_keylen);
+			}
+			break;
+		}
+		case PROTO_ISAKMP: {
+			struct alg_info_ike *ai_ike;
+			struct ike_info *ike_info;
+			enames=&oakley_enc_names;
+			anames=&oakley_hash_names;
+			gnames=&oakley_group_names;
+			ai_ike = alg_info_ike_create_from_str(str, &err);
+			ai = (struct alg_info *) ai_ike;
+			if (!ai) goto err;
+			alg_info_addref(ai);
+			ALG_INFO_IKE_FOREACH(ai_ike, ike_info, i) {
+				printf("(%d = \"%s\" [%d], ", 
+					ike_info->ike_ealg, 
+					enum_name(enames, ike_info->ike_ealg),
+					ike_info->ike_eklen);
+				printf("%d = \"%s\" [%d], ", 
+					ike_info->ike_halg,
+					enum_name(anames, ike_info->ike_halg),
+					ike_info->ike_hklen);
+				printf("%d = \"%s\")\n", 
+					ike_info->ike_modp,
+					ike_info->ike_modp ?
+					  enum_name(gnames, ike_info->ike_modp):
+					  "<default>");
+			}
+			break;
+		}
+	}
+	if (!ai) goto err;
+	{
+		char buf[256];
+		alg_info_snprint(buf, sizeof(buf), ai);
+		puts(buf);
+	}
+	alg_info_delref(&ai);
+	return 0;
+err:
+	if (err) 
+		fprintf(stderr, "ERROR: %s\n", err);
+	return 1;
+}
+int main(int argc, char *argv[])
+{
+	int c=0;
+	int protoid=0;
+	char *str;
+	while (1) {
+		c = getopt(argc, (char**)argv, "ie");
+		if (c == -1)
+			break;
+		switch (c) {
+			case 'i':
+				protoid=PROTO_ISAKMP;
+				break;
+			case 'e':
+				protoid=PROTO_IPSEC_ESP;
+				break;
+		}
+	}
+	if (!protoid || optind ==(argc)) {
+		fprintf(stderr, "usage: %s {-i|-e} algo string, eg: \n", 
+				argv[0]);
+		fprintf(stderr, "       -i " STR_EXAMPLE_IKE "\n");
+		fprintf(stderr, "       -e " STR_EXAMPLE_ESP "\n" );
+		return 1;
+	}
+	str=argv[optind];
+
+	setup_debugging();
+	doit(protoid, str);
+	return 0;
+}
+/* 
+ * 	Fake to allow build
+ */
+#define FUNC_NOT_CALLED(func) \
+int func(void); int func(void) { abort(); }
+FUNC_NOT_CALLED(ike_alg_init);
+FUNC_NOT_CALLED(MD5Init);
+FUNC_NOT_CALLED(MD5Update);
+FUNC_NOT_CALLED(MD5Final);
+FUNC_NOT_CALLED(SHA1Init);
+FUNC_NOT_CALLED(SHA1Update);
+FUNC_NOT_CALLED(SHA1Final);
+FUNC_NOT_CALLED(state_with_serialno);
+void exit_pluto(int st) {
+    exit(st);
+}
+void
+fmt_conn_instance(const struct connection *c __attribute__ ((unused)), char *buf __attribute__ ((unused)));
+void fmt_conn_instance(const struct connection *c __attribute__ ((unused)), char *buf __attribute__ ((unused))) {
+} 
Index: freeswan/pluto/connections.c
diff -u freeswan/pluto/connections.c:1.1.1.1.6.3 freeswan/pluto/connections.c:1.1.1.1.6.1.2.6
--- freeswan/pluto/connections.c:1.1.1.1.6.3	Fri Jul  5 00:16:22 2002
+++ freeswan/pluto/connections.c	Fri Jul  5 00:35:30 2002
@@ -46,6 +46,9 @@
 #include "adns.h"	/* needs <resolv.h> */
 #include "dnskey.h"	/* needs keys.h and adns.h */
 #include "whack.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+#include "kernel_alg.h"
 
 static void flush_pending_by_connection(struct connection *c);	/* forward */
 
@@ -294,6 +297,12 @@
     release_x509cert(c->that.cert);
     pfreeany(c->that.updown);
     gw_delref(&c->gw_info);
+#ifndef NO_KERNEL_ALG
+    alg_info_delref((struct alg_info **)&c->alg_info_esp);
+#endif
+#ifndef NO_IKE_ALG
+    alg_info_delref((struct alg_info **)&c->alg_info_ike);
+#endif
     pfree(c);
 }
 
@@ -735,6 +744,58 @@
 		, "ignoring --compress in \"%s\" because KLIPS is not configured to do IPCOMP"
 		, c->name);
 
+#ifndef NO_KERNEL_ALG
+	/* if (wm->esp)  */
+	{
+		const char *ugh;
+		DBG_log("from whack: got --esp=%s", wm->esp ? wm->esp: "NULL");
+		c->alg_info_esp= alg_info_esp_create_from_str(wm->esp? wm->esp : "", &ugh);
+		DBG(DBG_CRYPT|DBG_CONTROL, 
+			static char buf[256]="<NULL>";
+			if (c->alg_info_esp)
+				alg_info_snprint(buf, sizeof(buf), 
+					(struct alg_info *)c->alg_info_esp);
+			DBG_log("esp string values: %s", buf);
+		);
+		if (c->alg_info_esp) {
+			if (c->alg_info_esp->alg_info_cnt==0) {
+				loglog(RC_LOG_SERIOUS
+					, "got 0 transforms for esp=\"%s\""
+					, wm->esp);
+			}
+		} else {
+			loglog(RC_LOG_SERIOUS
+				, "esp string error: %s"
+				, ugh? ugh : "Unknown");
+		}
+	}
+#endif	
+#ifndef NO_IKE_ALG
+	/* if (wm->ike) */
+	{
+		const char *ugh;
+		DBG_log("from whack: got --ike=%s", wm->ike ? wm->ike: "NULL");
+		c->alg_info_ike= alg_info_ike_create_from_str(wm->ike? wm->ike : "", &ugh);
+		DBG(DBG_CRYPT|DBG_CONTROL, 
+				static char buf[256]="<NULL>";
+				if (c->alg_info_ike)
+					alg_info_snprint(buf, sizeof(buf),
+						(struct alg_info *)c->alg_info_ike);
+				DBG_log("ike string values: %s", buf);
+				);
+		if (c->alg_info_ike) {
+			if (c->alg_info_ike->alg_info_cnt==0) {
+				loglog(RC_LOG_SERIOUS
+					, "got 0 transforms for ike=\"%s\""
+					, wm->ike);
+			}
+		} else {
+			loglog(RC_LOG_SERIOUS
+				, "ike string error: %s"
+				, ugh? ugh : "Unknown");
+		}
+	}
+#endif
 	c->sa_ike_life_seconds = wm->sa_ike_life_seconds;
 	c->sa_ipsec_life_seconds = wm->sa_ipsec_life_seconds;
 	c->sa_rekey_margin = wm->sa_rekey_margin;
@@ -779,6 +840,12 @@
 	c->gw_info = NULL;
 
 	unshare_connection_strings(c);
+#ifndef NO_KERNEL_ALG
+	alg_info_addref((struct alg_info *)c->alg_info_esp);
+#endif
+#ifndef NO_IKE_ALG
+	alg_info_addref((struct alg_info *)c->alg_info_ike);
+#endif
 
 	(void)orient(c);
 	connect_to_host_pair(c);
@@ -845,6 +912,12 @@
 	d->that.id = *his_id;
     }
     unshare_connection_strings(d);
+#ifndef NO_KERNEL_ALG
+    alg_info_addref((struct alg_info *)d->alg_info_esp);
+#endif
+#ifndef NO_IKE_ALG
+    alg_info_addref((struct alg_info *)d->alg_info_ike);
+#endif
 
     d->kind = CK_INSTANCE;
 
@@ -2082,6 +2155,12 @@
 	    , c->newest_isakmp_sa
 	    , c->newest_ipsec_sa
 	    , c->eroute_owner);
+#ifndef NO_IKE_ALG
+	ike_alg_show_connection(c, instance);
+#endif
+#ifndef NO_KERNEL_ALG
+	kernel_alg_show_connection(c, instance);
+#endif
     }
 }
 
Index: freeswan/pluto/connections.h
diff -u freeswan/pluto/connections.h:1.1.1.1.6.3 freeswan/pluto/connections.h:1.1.1.1.6.1.2.4
--- freeswan/pluto/connections.h:1.1.1.1.6.3	Fri Jul  5 00:16:22 2002
+++ freeswan/pluto/connections.h	Fri Jul  5 00:35:30 2002
@@ -138,6 +138,8 @@
     sa_family_t tunnel_addr_family;	/* between clients */
 
     struct gw_info *gw_info;
+    struct alg_info_esp *alg_info_esp;
+    struct alg_info_ike *alg_info_ike;
 
     struct host_pair *host_pair;
     struct connection *hp_next;	/* host pair list link */
@@ -201,6 +203,7 @@
  * is looking through state objects.
  */
 struct gw_info;	/* forward declaration of tag (defined in dnskey.h) */
+struct alg_info;	/* forward declaration of tag (defined in alg_info.h) */
 extern struct connection
     *rw_instantiate(struct connection *c, const ip_address *him
 	, const struct id *his_id),
Index: freeswan/pluto/constants.c
diff -u freeswan/pluto/constants.c:1.1.1.1.6.1 freeswan/pluto/constants.c:1.1.1.1.6.1.2.4
--- freeswan/pluto/constants.c:1.1.1.1.6.1	Fri May 24 19:17:53 2002
+++ freeswan/pluto/constants.c	Mon Jun  3 22:46:59 2002
@@ -277,11 +277,24 @@
 	"ESP_DES_IV32",
 	"ESP_RC4",
 	"ESP_NULL",
-	"ESP_AES",
+	"ESP_AES"
+};
+
+/*
+ * ipsec drafts suggest "high" ESP ids values for testing,
+ * assign generic ESP_ID<num> if not officially defined 
+ */
+static const char *const esp_transform_name_high[] = {
+	/* id=248 */	"ESP_ID248","ESP_MARS","ESP_RC6","ESP_ID251",
+	/* id=252 */	"ESP_SERPENT", "ESP_TWOFISH", "ESP_CAMELLIA", "ESP_ID255",
+	/* id=256 */	"ESP_ID256"
     };
 
+enum_names esp_transformid_names_high =
+    { 248, 256, esp_transform_name_high, NULL };
+
 enum_names esp_transformid_names =
-    { ESP_DES_IV64, ESP_AES, esp_transform_name, NULL };
+    { ESP_DES_IV64, ESP_AES, esp_transform_name, &esp_transformid_names_high };
 
 /* IPCOMP transform values */
 
@@ -498,11 +511,22 @@
 	"AUTH_ALGORITHM_HMAC_SHA1",
 	"AUTH_ALGORITHM_DES_MAC",
 	"AUTH_ALGORITHM_KPDK",
+	"AUTH_ALGORITHM_HMAC_SHA2_256",
+	"AUTH_ALGORITHM_HMAC_SHA2_384",
+	"AUTH_ALGORITHM_HMAC_SHA2_512",
+	"AUTH_ALGORITHM_HMAC_RIPEMD",
+	"AUTH_ALGORITHM_ID9",
+	"AUTH_ALGORITHM_ID10",
+	"AUTH_ALGORITHM_ID11",
+	"AUTH_ALGORITHM_ID12",
+	"AUTH_ALGORITHM_ID13",
+	"AUTH_ALGORITHM_ID14",
+	"AUTH_ALGORITHM_ID15",
     };
 
 enum_names
     auth_alg_names =
-	{ AUTH_ALGORITHM_HMAC_MD5, AUTH_ALGORITHM_KPDK, auth_alg_name + 1, NULL },
+	{ AUTH_ALGORITHM_HMAC_MD5, 15 /* AUTH_ALGORITHM_HMAC_RIPEMD */, auth_alg_name + 1, NULL },
     extended_auth_alg_names =
 	{ AUTH_ALGORITHM_NONE, AUTH_ALGORITHM_KPDK, auth_alg_name, NULL };
 
@@ -533,8 +557,27 @@
 	"OAKLEY_AES_CBC",
     };
 
+#ifdef NO_EXTRA_IKE
 enum_names oakley_enc_names =
     { OAKLEY_DES_CBC, OAKLEY_AES_CBC, oakley_enc_name, NULL };
+#else
+static const char *const oakley_enc_name_draft_aes_cbc_02[] = {
+	"OAKLEY_MARS_CBC"	/*	65001	*/,
+	"OAKLEY_RC6_CBC"     	/*	65002	*/,
+	"OAKLEY_ID_65003"	/*	65003	*/,
+	"OAKLEY_SERPENT_CBC"	/*	65004	*/,
+	"OAKLEY_TWOFISH_CBC"	/*	65005	*/,
+};
+static const char *const oakley_enc_name_ssh[] = {
+	"OAKLEY_SSH_PRIVATE_65289",
+};
+enum_names oakley_enc_names_ssh =
+    { 65289, 65289, oakley_enc_name_ssh, NULL };
+enum_names oakley_enc_names_draft_aes_cbc_02 =
+    { 65001, 65005, oakley_enc_name_draft_aes_cbc_02, &oakley_enc_names_ssh };
+enum_names oakley_enc_names =
+    { OAKLEY_DES_CBC, OAKLEY_AES_CBC, oakley_enc_name, &oakley_enc_names_draft_aes_cbc_02 };
+#endif
 
 /* Oakley Hash Algorithm attribute */
 
@@ -604,8 +647,31 @@
 	"OAKLEY_GROUP_MODP1536 (extension)",
     };
 
+static const char *const oakley_group_name_2048[] = {
+	"OAKLEY_GROUP_MODP2048 (extension)",
+};
+static const char *const oakley_group_name_3072[] = {
+	"OAKLEY_GROUP_MODP3072 (extension)",
+};
+static const char *const oakley_group_name_4096[] = {
+	"OAKLEY_GROUP_MODP4096 (extension)",
+};
+
+enum_names oakley_group_names_4096 =
+    { OAKLEY_GROUP_MODP4096, OAKLEY_GROUP_MODP4096, 
+	    oakley_group_name_4096, NULL };
+
+enum_names oakley_group_names_3072 =
+    { OAKLEY_GROUP_MODP3072, OAKLEY_GROUP_MODP3072, 
+	    oakley_group_name_3072, &oakley_group_names_4096 };
+
+enum_names oakley_group_names_2048 =
+    { OAKLEY_GROUP_MODP2048, OAKLEY_GROUP_MODP2048, 
+	    oakley_group_name_2048, &oakley_group_names_3072 };
+
 enum_names oakley_group_names =
-    { OAKLEY_GROUP_MODP768, OAKLEY_GROUP_MODP1536, oakley_group_name, NULL };
+    { OAKLEY_GROUP_MODP768, OAKLEY_GROUP_MODP1536, 
+	    oakley_group_name, &oakley_group_names_2048 };
 
 /* Oakley Group Type attribute */
 
@@ -825,6 +891,23 @@
     return p;
 }
 
+int 
+enum_search(enum_names *ed, const char *str) 
+{
+    enum_names	*p;
+    const char *ptr;
+    unsigned en;
+
+    for (p = ed; p != NULL; p = p->en_next_range)
+	for (en=p->en_first;en<=p->en_last;en++) {
+	    ptr=p->en_names[en - p->en_first];
+	    if (ptr==0) continue;
+	    /* if (strncmp(ptr, str, strlen(ptr))==0) */
+	    if (strcmp(ptr, str)==0)
+		    return en;
+	}
+    return -1;
+}
 /* construct a string to name the bits on in a set
  * Result may be in STATIC buffer!
  */
@@ -847,9 +930,10 @@
 	    if (n == NULL || *n == '\0')
 	    {
 		/* no name for this bit, so use hex */
-		static char flagbuf[sizeof("0x80000000")];
+		/* 64bits lset_t */
+		static char flagbuf[sizeof("0x80000000" "00000000")]; 
 
-		snprintf(flagbuf, sizeof(flagbuf), "0x%lx", bit);
+		snprintf(flagbuf, sizeof(flagbuf), "0x%llx", bit);
 		n = flagbuf;
 	    }
 
Index: freeswan/pluto/constants.h
diff -u freeswan/pluto/constants.h:1.1.1.1.6.1 freeswan/pluto/constants.h:1.1.1.1.6.1.2.5
--- freeswan/pluto/constants.h:1.1.1.1.6.1	Fri May 24 19:17:53 2002
+++ freeswan/pluto/constants.h	Wed Jun  5 19:10:29 2002
@@ -47,9 +47,9 @@
 
 /* set type with room for at least 32 elements */
 
-typedef unsigned long lset_t;
-#define LEMPTY 0UL
-#define LELEM(opt) (1UL << (opt))
+typedef unsigned long long lset_t;
+#define LEMPTY 0ULL
+#define LELEM(opt) (1ULL << (opt))
 #define LRANGE(lwb, upb) LRANGES(LELEM(lwb), LELEM(upb))
 #define LRANGES(first, last) (last - first + last)
 #define LALLIN(set, probe)	(((set) & (probe)) == (probe))
@@ -77,6 +77,7 @@
 
 extern const char *enum_name(enum_names *ed, unsigned long val);
 extern const char *enum_show(enum_names *ed, unsigned long val);
+extern int enum_search(enum_names *ed, const char *string);
 
 extern bool testset(const char *const table[], lset_t val);
 extern const char *bitnamesof(const char *const table[], lset_t val);
@@ -127,6 +128,62 @@
     "83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D " \
     "670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF "
 
+/* draft-ietf-ipsec-ike-modp-groups-03.txt */
+#define MODP2048_MODULUS \
+	"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+	"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+	"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+	"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+	"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+	"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+	"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+	"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+	"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+	"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+	"15728E5A 8AACAA68 FFFFFFFF FFFFFFFF"
+
+#define MODP3072_MODULUS \
+	"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+	"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+	"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+	"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+	"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+	"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+	"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+	"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+	"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+	"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+	"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \
+	"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \
+	"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \
+	"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \
+	"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \
+	"43DB5BFC E0FD108E 4B82D120 A93AD2CA FFFFFFFF FFFFFFFF"
+
+#define MODP4096_MODULUS \
+	"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1" \
+	"29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD" \
+	"EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245" \
+	"E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED" \
+	"EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D" \
+	"C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F" \
+	"83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D" \
+	"670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B" \
+	"E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9" \
+	"DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510" \
+	"15728E5A 8AAAC42D AD33170D 04507A33 A85521AB DF1CBA64" \
+	"ECFB8504 58DBEF0A 8AEA7157 5D060C7D B3970F85 A6E1E4C7" \
+	"ABF5AE8C DB0933D7 1E8C94E0 4A25619D CEE3D226 1AD2EE6B" \
+	"F12FFA06 D98A0864 D8760273 3EC86A64 521F2B18 177B200C" \
+	"BBE11757 7A615D6C 770988C0 BAD946E2 08E24FA0 74E5AB31" \
+	"43DB5BFC E0FD108E 4B82D120 A9210801 1A723C12 A787E6D7" \
+	"88719A10 BDBA5B26 99C32718 6AF4E23C 1A946834 B6150BDA" \
+	"2583E9CA 2AD44CE8 DBBBC2DB 04DE8EF9 2E8EFC14 1FBECAA6" \
+	"287C5947 4E6BC05D 99B2964F A090C3A2 233BA186 515BE7ED" \
+	"1F612970 CEE2D7AF B81BDD76 2170481C D0069127 D5B05AA9" \
+	"93B4EA98 8D8FDDC1 86FFB7DC 90A6C08F 4DF435C9 34063199" \
+	"FFFFFFFF FFFFFFFF"
+
 #define LOCALSECRETSIZE		(256 / BITS_PER_BYTE)
 
 /* limits on nonce sizes.  See RFC2409 "The internet key exchange (IKE)" 5 */
@@ -149,8 +206,10 @@
  * MD5_DIGEST_SIZE, SHA1_DIGEST_SIZE, and DES_CBC_BLOCK_SIZE.
  * To avoid combinatorial explosion, we leave out DES_CBC_BLOCK_SIZE.
  */
-#define MAX_DIGEST_LEN (MD5_DIGEST_SIZE > SHA1_DIGEST_SIZE? MD5_DIGEST_SIZE : SHA1_DIGEST_SIZE)
+#define MAX_DIGEST_LEN_OLD (MD5_DIGEST_SIZE > SHA1_DIGEST_SIZE? MD5_DIGEST_SIZE : SHA1_DIGEST_SIZE)
 
+/* for max: SHA2_512 */
+#define MAX_DIGEST_LEN (512/BITS_PER_BYTE)
 /* draft-ietf-ipsec-auth-hmac-sha196-01.txt section 3 */
 #define HMAC_SHA1_KEY_LEN    SHA1_DIGEST_SIZE
 
@@ -663,6 +722,11 @@
 #define AUTH_ALGORITHM_HMAC_SHA1   2
 #define AUTH_ALGORITHM_DES_MAC     3
 #define AUTH_ALGORITHM_KPDK        4
+#define AUTH_ALGORITHM_HMAC_SHA2_256   5
+#define AUTH_ALGORITHM_HMAC_SHA2_384   6
+#define AUTH_ALGORITHM_HMAC_SHA2_512   7
+#define AUTH_ALGORITHM_HMAC_RIPEMD     8
+
 
 /* Oakley Lifetime Type attribute
  * draft-ietf-ipsec-ike-01.txt appendix A
@@ -705,6 +769,8 @@
 #define OAKLEY_CAST_CBC         6
 #define OAKLEY_AES_CBC          7
 
+#define OAKLEY_ENCRYPT_MAX      65535	/* pretty useless :) */
+
 /* Oakley Hash Algorithm attribute
  * draft-ietf-ipsec-ike-01.txt appendix A
  * and from http://www.isi.edu/in-notes/iana/assignments/ipsec-registry
@@ -719,6 +785,8 @@
 #define OAKLEY_SHA2_384        5
 #define OAKLEY_SHA2_512        6
 
+#define OAKLEY_HASH_MAX      7
+
 /* Oakley Authentication Method attribute
  * draft-ietf-ipsec-ike-01.txt appendix A
  * Goofy Hybrid extensions from draft-ietf-ipsec-isakmp-hybrid-auth-05.txt
@@ -763,6 +831,11 @@
 #define OAKLEY_GROUP_GP155         3
 #define OAKLEY_GROUP_GP185         4
 #define OAKLEY_GROUP_MODP1536      5
+
+/*	you must also touch: constants.c, crypto.c */
+#define OAKLEY_GROUP_MODP2048      42048
+#define OAKLEY_GROUP_MODP3072      43072
+#define OAKLEY_GROUP_MODP4096      44096
 
 /* Oakley Group Type attribute
  * draft-ietf-ipsec-ike-01.txt appendix A
Index: freeswan/pluto/crypto.c
diff -u freeswan/pluto/crypto.c:1.1.1.1.6.1 freeswan/pluto/crypto.c:1.1.1.1.4.5
--- freeswan/pluto/crypto.c:1.1.1.1.6.1	Fri Jul  5 00:16:22 2002
+++ freeswan/pluto/crypto.c	Fri Jul  5 00:35:30 2002
@@ -18,6 +18,7 @@
 #include <string.h>
 #include <stddef.h>
 #include <sys/types.h>
+#include <errno.h>
 
 #include <freeswan.h>
 #define HEADER_DES_LOCL_H   /* stupid trick to force prototype decl in <des.h> */
@@ -30,6 +31,8 @@
 #include "md5.h"
 #include "sha1.h"
 #include "crypto.h" /* requires sha1.h and md5.h */
+#include "alg_info.h"
+#include "ike_alg.h"
 
 
 /* moduli and generator. */
@@ -40,10 +43,50 @@
     modp768_modulus,
 #endif
     modp1024_modulus,
-    modp1536_modulus;
+    modp1536_modulus,
+    modp2048_modulus,
+    modp3072_modulus,
+    modp4096_modulus;
 
 MP_INT groupgenerator;	/* MODP group generator (2) */
 
+#ifndef NO_IKE_ALG
+static void do_3des(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc);
+static struct encrypt_desc crypto_encrypter_3des =
+{ 	
+	algo_type: 	IKE_ALG_ENCRYPT,
+	algo_id:   	OAKLEY_3DES_CBC, 
+	algo_next: 	NULL, 
+	enc_ctxsize: 	sizeof(des_key_schedule) * 3,
+	enc_blocksize: 	DES_CBC_BLOCK_SIZE, 
+	keydeflen: 	DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE,
+	keyminlen: 	DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE,
+	keymaxlen: 	DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE,
+	do_crypt: 	do_3des,
+};
+static struct hash_desc crypto_hasher_md5 =
+{ 	
+	algo_type: IKE_ALG_HASH,
+	algo_id:   OAKLEY_MD5,
+	algo_next: NULL, 
+	hash_ctx_size: sizeof(MD5_CTX),
+	hash_digest_size: MD5_DIGEST_SIZE,
+	hash_init: (void (*)(void *)) MD5Init,
+	hash_update: (void (*)(void *, const u_int8_t *, size_t)) MD5Update,
+	hash_final: (void (*)(u_char *, void *)) MD5Final,
+};
+static struct hash_desc crypto_hasher_sha1 =
+{ 	
+	algo_type: IKE_ALG_HASH,
+	algo_id:   OAKLEY_SHA,
+	algo_next: NULL, 
+	hash_ctx_size: sizeof(SHA1_CTX),
+	hash_digest_size: SHA1_DIGEST_SIZE,
+	hash_init: (void (*)(void *)) SHA1Init,
+	hash_update: (void (*)(void *, const u_int8_t *, size_t)) SHA1Update,
+	hash_final: (void (*)(u_char *, void *)) SHA1Final,
+};
+#endif
 void
 init_crypto(void)
 {
@@ -52,8 +95,20 @@
     || mpz_init_set_str(&modp768_modulus, MODP768_MODULUS, 16) != 0
 #endif
     || mpz_init_set_str(&modp1024_modulus, MODP1024_MODULUS, 16) != 0
-    || mpz_init_set_str(&modp1536_modulus, MODP1536_MODULUS, 16) != 0)
+    || mpz_init_set_str(&modp1536_modulus, MODP1536_MODULUS, 16) != 0
+    || mpz_init_set_str(&modp2048_modulus, MODP2048_MODULUS, 16) != 0
+    || mpz_init_set_str(&modp3072_modulus, MODP3072_MODULUS, 16) != 0
+    || mpz_init_set_str(&modp4096_modulus, MODP4096_MODULUS, 16) != 0)
 	exit_log("mpz_init_set_str() failed in init_crypto()");
+#ifndef NO_IKE_ALG
+	{ 
+		extern int ike_alg_init(void);
+		ike_alg_add((struct ike_alg *) &crypto_encrypter_3des);
+		ike_alg_add((struct ike_alg *) &crypto_hasher_md5);
+		ike_alg_add((struct ike_alg *) &crypto_hasher_sha1);
+		ike_alg_init();
+	}
+#endif
 }
 
 /* Oakley group description
@@ -63,13 +118,16 @@
 
 const struct oakley_group_desc unset_group = {0, NULL, 0};	/* magic signifier */
 
-static const struct oakley_group_desc oakley_group[] = {
+const struct oakley_group_desc oakley_group[OAKLEY_GROUP_SIZE] = {
 #   define BYTES(bits) (((bits) + BITS_PER_BYTE - 1) / BITS_PER_BYTE)
 #if 0	/* modp768 not sufficiently strong */
     { OAKLEY_GROUP_MODP768, &modp768_modulus, BYTES(768) },
 #endif
     { OAKLEY_GROUP_MODP1024, &modp1024_modulus, BYTES(1024) },
     { OAKLEY_GROUP_MODP1536, &modp1536_modulus, BYTES(1536) },
+    { OAKLEY_GROUP_MODP2048, &modp2048_modulus, BYTES(2048) },
+    { OAKLEY_GROUP_MODP3072, &modp3072_modulus, BYTES(3072) },
+    { OAKLEY_GROUP_MODP4096, &modp4096_modulus, BYTES(4096) },
 #   undef BYTES
 };
 
@@ -93,7 +151,7 @@
 /* encrypt or decrypt part of an IKE message using DES
  * See draft-ietf-ipsec-isakmp-oakley-07.txt Appendix B
  */
-static void
+static void __attribute__ ((unused))
 do_des(bool enc, void *buf, size_t buf_len, struct state *st)
 {
     des_key_schedule ks;
@@ -112,57 +170,46 @@
  * See draft-ietf-ipsec-isakmp-oakley-07.txt Appendix B
  */
 static void
-do_3des(bool enc, void *buf, size_t buf_len, struct state *st)
+do_3des(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
 {
     des_key_schedule ks[3];
 
-    (void) des_set_key((des_cblock *)st->st_enc_key.ptr + 0, ks[0]);
-    (void) des_set_key((des_cblock *)st->st_enc_key.ptr + 1, ks[1]);
-    (void) des_set_key((des_cblock *)st->st_enc_key.ptr + 2, ks[2]);
-
-    passert(st->st_new_iv_len >= DES_CBC_BLOCK_SIZE);
-    st->st_new_iv_len = DES_CBC_BLOCK_SIZE;	/* truncate */
+    passert (!key_size || (key_size==(DES_CBC_BLOCK_SIZE * 3)))
+    (void) des_set_key((des_cblock *)key + 0, ks[0]);
+    (void) des_set_key((des_cblock *)key + 1, ks[1]);
+    (void) des_set_key((des_cblock *)key + 2, ks[2]);
 
     des_ede3_cbc_encrypt((des_cblock *)buf, (des_cblock *)buf, buf_len,
 	ks[0], ks[1], ks[2],
-	(des_cblock *)st->st_new_iv, enc);
+	(des_cblock *)iv, enc);
 }
-
-const struct encrypt_desc oakley_encrypter[OAKLEY_CAST_CBC + 1] = {
-    /* (none) */
-	{ 0, 0, NULL },
-    /* OAKLEY_DES_CBC */
-	{ DES_CBC_BLOCK_SIZE, DES_CBC_BLOCK_SIZE, do_des },
-    /* OAKLEY_IDEA_CBC */
-	{ 0, 0, NULL },
-    /* OAKLEY_BLOWFISH_CBC */
-	{ 0, 0, NULL },
-    /* OAKLEY_RC5_R16_B64_CBC */
-	{ 0, 0, NULL },
-    /* OAKLEY_3DES_CBC */
-	{ DES_CBC_BLOCK_SIZE, DES_CBC_BLOCK_SIZE * 3, do_3des },
-    /* OAKLEY_CAST_CBC */
-	{ 0, 0, NULL },
-    };
-
 /* hash and prf routines */
+/*========================================================== 
+ *
+ *  ike_alg linked list
+ *
+ *==========================================================
+ */
+struct hash_desc *crypto_get_hasher(int alg)
+{
+	return (struct hash_desc *) ike_alg_find(IKE_ALG_HASH, alg, 0);
+}
+struct encrypt_desc *crypto_get_encrypter(int alg)
+{
+	return (struct encrypt_desc *) ike_alg_find(IKE_ALG_ENCRYPT, alg, 0);
+}
+void 
+crypto_cbc_encrypt(const struct encrypt_desc *e, bool enc, u_int8_t *buf, size_t size, struct state *st)
+{
+    passert(st->st_new_iv_len >= e->enc_blocksize);
+    st->st_new_iv_len = e->enc_blocksize;	/* truncate */
 
-const struct hash_desc oakley_hasher[OAKLEY_TIGER+1] = {
-	{ 0, NULL, NULL, NULL },	/* no specified hasher */
-
-	{ MD5_DIGEST_SIZE,
-	    (void (*)(union hash_ctx *)) MD5Init,
-	    (void (*)(union hash_ctx *, const u_char *, unsigned int)) MD5Update,
-	    (void (*)(u_char *, union hash_ctx *)) MD5Final},	/* OAKLEY_MD5 */
-
-	{ SHA1_DIGEST_SIZE,
-	    (void (*)(union hash_ctx *)) SHA1Init,
-	    (void (*)(union hash_ctx *, const u_char *, unsigned int)) SHA1Update,
-	    (void (*)(u_char *, union hash_ctx *)) SHA1Final},	/* OAKLEY_SHA */
-
-	{ 0, NULL, NULL, NULL }	/* OAKLEY_TIGER */
-    };
-
+    e->do_crypt(buf, size, st->st_enc_key.ptr, st->st_enc_key.len, st->st_new_iv, enc);
+    /*
+    e->set_key(&ctx, st->st_enc_key.ptr, st->st_enc_key.len);
+    e->cbc_crypt(&ctx, buf, size, st->st_new_iv, enc);
+    */
+}
 /* HMAC package
  * rfc2104.txt specifies how HMAC works.
  */
@@ -175,7 +222,7 @@
     int k;
 
     ctx->h = h;
-    ctx->hmac_digest_len = h->hash_digest_len;
+    ctx->hmac_digest_size = h->hash_digest_size;
 
     /* Prepare the two pads for the HMAC */
 
@@ -226,6 +273,6 @@
 
     h->hash_init(&ctx->hash_ctx);
     h->hash_update(&ctx->hash_ctx, ctx->buf2, HMAC_BUFSIZE);
-    h->hash_update(&ctx->hash_ctx, output, h->hash_digest_len);
+    h->hash_update(&ctx->hash_ctx, output, h->hash_digest_size);
     h->hash_final(output, &ctx->hash_ctx);
 }
Index: freeswan/pluto/crypto.h
diff -u freeswan/pluto/crypto.h:1.1.1.1 freeswan/pluto/crypto.h:1.1.1.1.4.2
--- freeswan/pluto/crypto.h:1.1.1.1	Sun Dec 12 21:40:50 1999
+++ freeswan/pluto/crypto.h	Fri May 31 00:29:32 2002
@@ -30,6 +30,8 @@
 
 extern const struct oakley_group_desc unset_group;	/* magic signifier */
 extern const struct oakley_group_desc *lookup_group(u_int16_t group);
+#define OAKLEY_GROUP_SIZE 5
+extern const struct oakley_group_desc oakley_group[OAKLEY_GROUP_SIZE];
 
 /* unification of cryptographic encoding/decoding algorithms
  * The IV is taken from and returned to st->st_new_iv.
@@ -38,38 +40,29 @@
  * been validated).
  */
 
-#define MAX_OAKLEY_KEY_LEN  (3 * DES_CBC_BLOCK_SIZE)
+#define MAX_OAKLEY_KEY_LEN0  (3 * DES_CBC_BLOCK_SIZE)
+#define MAX_OAKLEY_KEY_LEN  (256/BITS_PER_BYTE)
 
 struct state;	/* forward declaration, dammit */
 
-struct encrypt_desc {
-    size_t blocksize;
-    size_t keysize;
-    void (*crypt)(bool enc, void *buf, size_t buf_len, struct state *st);
-};
-
-const struct encrypt_desc oakley_encrypter[OAKLEY_CAST_CBC + 1];
-
+struct encrypt_desc;
+struct hash_desc;
+struct encrypt_desc *crypto_get_encrypter(int alg);
+struct hash_desc *crypto_get_hasher(int alg);
+void crypto_cbc_encrypt(const struct encrypt_desc *e, bool enc, u_int8_t *buf, size_t size, struct state *st);
 #define update_iv(st)	memcpy((st)->st_iv, (st)->st_new_iv \
     , (st)->st_iv_len = (st)->st_new_iv_len)
 
 /* unification of cryptographic hashing mechanisms */
 
+#ifndef NO_HASH_CTX
 union hash_ctx {
 	MD5_CTX ctx_md5;
 	SHA1_CTX ctx_sha1;
+	char ctx_sha256[108];	/* This is _ugly_ [TM], but avoids */
+	char ctx_sha512[212];	/* header coupling (is checked at runtime */
     };
 
-struct hash_desc {
-    size_t hash_digest_len; /* length of digest */
-    void (*hash_init)(union hash_ctx *);	/* initialize context */
-    void (*hash_update)(union hash_ctx *, const u_char *input, unsigned int len);   /* add input to hash */
-    void (*hash_final)(u_char *output, union hash_ctx *);   /* finalize hash */
-};
-
-extern const struct hash_desc oakley_hasher[OAKLEY_TIGER+1];
-
-
 /* HMAC package
  * Note that hmac_ctx can be (and is) copied since there are
  * no persistent pointers into it.
@@ -77,7 +70,7 @@
 
 struct hmac_ctx {
     const struct hash_desc *h;	/* underlying hash function */
-    size_t hmac_digest_len;	/* copy of h->hash_digest_len */
+    size_t hmac_digest_size;	/* copy of h->hash_digest_size */
     union hash_ctx hash_ctx;	/* ctx for hash function */
     u_char buf1[HMAC_BUFSIZE], buf2[HMAC_BUFSIZE];
     };
@@ -103,7 +96,8 @@
 
 #define hmac_final_chunk(ch, name, ctx) { \
 	pfreeany((ch).ptr); \
-	(ch).len = (ctx)->hmac_digest_len; \
+	(ch).len = (ctx)->hmac_digest_size; \
 	(ch).ptr = alloc_bytes((ch).len, name); \
 	hmac_final((ch).ptr, (ctx)); \
     }
+#endif
Index: freeswan/pluto/db_ops.c
diff -u /dev/null freeswan/pluto/db_ops.c:1.1.4.3
--- /dev/null	Fri Jul 12 16:03:46 2002
+++ freeswan/pluto/db_ops.c	Mon Jul  8 09:05:40 2002
@@ -0,0 +1,421 @@
+/* 
+ * Dynamic db (proposal, transforms, attributes) handling.
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ * 
+ * $Id: db_ops.c,v 1.1.4.3 2002/07/08 12:05:40 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.
+ */
+
+/* 
+ * The stratedy is to have (full contained) struct db_prop in db_context
+ * pointing to ONE dynamically sizable transform vector (trans0).
+ * Each transform stores attrib. in ONE dyn. sizable attribute vector (attrs0)
+ * in a "serialized" way (attributes storage is used in linear sequence for 
+ * subsecuent transforms).
+ *
+ * Resizing for both trans0 and attrs0 is supported:
+ * - For trans0: quite simple, just allocate and copy trans. vector content
+ *               also update trans_cur (by offset)
+ * - For attrs0: after allocating and copying attrs, I must rewrite each
+ *               trans->attrs present in trans0; to achieve this, calculate
+ *               attrs pointer offset (new minus old) and iterate over 
+ *               each transform "adding" this difference.
+ *               also update attrs_cur (by offset)
+ *
+ * db_context structure:
+ * 	+---------------------+
+ *	|  prop               |
+ *	|    .protoid         |
+ *	|    .trans           | --+
+ *	|    .trans_cnt       |   |
+ *	+---------------------+ <-+
+ *	|  trans0             | ----> { trans#1 | ... | trans#i | ...   }
+ *	+---------------------+                       ^
+ *	|  trans_cur          | ----------------------' current transf.
+ *	+---------------------+
+ *	|  attrs0             | ----> { attr#1 | ... | attr#j | ...  }
+ *	+---------------------+                      ^
+ *	|  attrs_cur          | ---------------------' current attr.
+ *	+---------------------+
+ *	| max_trans,max_attrs |  max_trans/attrs: number of elem. of each vector
+ *	+---------------------+
+ *
+ * See testing examples at end for interface usage.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <malloc.h>
+#include <sys/types.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "state.h"
+#include "packet.h"
+#include "spdb.h"
+#include "db_ops.h"
+#include "log.h"
+#include "whack.h"
+
+#include <assert.h>
+
+#ifndef NO_PLUTO
+#else
+#define passert(x) assert(x)
+extern int debug;	/* eg: spi.c */
+#define DBG(cond, action)   { if (debug) { action ; } }
+#define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args);
+#define alloc_thing(thing, name) alloc_bytes(sizeof (thing), name)
+void * alloc_bytes(size_t size, const char *name) {
+	void *p=malloc(size);
+        if (p == NULL)
+		fprintf(stderr, "unable to malloc %lu bytes for %s",
+			(unsigned long) size, name);
+	memset(p, '\0', size);
+	return p;
+}
+#define pfreeany(ptr) free(ptr)
+
+#endif
+
+#ifdef NOT_YET
+/*
+ * 	Allocator cache:
+ * 	Because of the single-threaded nature of pluto/spdb.c, 
+ * 	alloc()/free() is exercised many times with very small
+ * 	lifetime objects.
+ * 	Just caching last object (currently it will select the
+ * 	largest) will avoid this allocation mas^Wperturbations
+ *
+ */
+struct db_ops_alloc_cache {
+	void *ptr;
+	int size;
+};
+#endif
+
+#ifndef NO_DB_OPS_STATS
+/* 	
+ * 	stats: do account for allocations 	
+ * 	displayed in db_ops_show_status() 
+ */
+struct db_ops_stats {
+	int st_curr_cnt;	/* current number of allocations */
+	int st_total_cnt;	/* total allocations so far */
+	size_t st_maxsz;	/* max. size requested */
+};
+#define DB_OPS_ZERO { 0, 0, 0};
+#define DB_OPS_STATS_DESC   "{curr_cnt, total_cnt, maxsz}"
+#define DB_OPS_STATS_STR(name)  name "={%d,%d,%d} "
+#define DB_OPS_STATS_F(st) (st).st_curr_cnt, (st).st_total_cnt, (st).st_maxsz
+static struct db_ops_stats db_context_st = DB_OPS_ZERO;
+static struct db_ops_stats db_trans_st = DB_OPS_ZERO;
+static struct db_ops_stats db_attrs_st = DB_OPS_ZERO;
+static __inline__ void * alloc_bytes_st (size_t size, const char *str, struct db_ops_stats *st) 
+{
+	void *ptr = alloc_bytes(size, str);
+	if (ptr)  {
+		st->st_curr_cnt++;
+		st->st_total_cnt++;
+		if (size > st->st_maxsz) st->st_maxsz=size;
+	}	
+	return ptr;
+}
+#define ALLOC_BYTES_ST(z,s,st) alloc_bytes_st(z, s, &st);
+#define PFREE_ST(p,st)         do { st.st_curr_cnt--; pfree(p);  } while (0);
+
+#else
+
+#define ALLOC_BYTES_ST(z,s,n) alloc_bytes(z, s);
+#define PFREE_ST(p,n)         pfree(p);
+
+#endif /* NO_DB_OPS_STATS */
+/*	Initialize db object
+ *	max_trans and max_attrs can be 0, will be dynamically expanded
+ *	as a result of "add" operations
+ */
+int
+db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs) 
+{
+	int ret=-1;
+
+	ctx->trans0 = NULL;
+	ctx->attrs0 = NULL;
+
+	if (max_trans > 0) { /* quite silly if not */
+		ctx->trans0 = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans, 
+			"db_context->trans", db_trans_st);
+		if (!ctx->trans0) goto out;
+	}
+
+	if (max_attrs > 0) { /* quite silly if not */
+		ctx->attrs0 = ALLOC_BYTES_ST (sizeof (struct db_attr) * max_attrs,
+				"db_context->attrs", db_attrs_st);
+		if (!ctx->attrs0) goto out;
+	}
+	ret = 0;
+out:
+	if (ret < 0 && ctx->trans0) {
+		PFREE_ST(ctx->trans0, db_trans_st);
+		ctx->trans0 = NULL;
+	}
+	ctx->max_trans = max_trans;
+	ctx->max_attrs = max_attrs;
+	ctx->trans_cur = ctx->trans0;
+	ctx->attrs_cur = ctx->attrs0;
+	ctx->prop.protoid = protoid;
+	ctx->prop.trans = ctx->trans0;
+	ctx->prop.trans_cnt = 0;
+	return ret;
+}
+
+/*	Expand storage for transforms by number delta_trans */
+static int
+db_trans_expand(struct db_context *ctx, int delta_trans)
+{
+	int ret = -1;
+	struct db_trans *new_trans, *old_trans;
+	int max_trans = ctx->max_trans + delta_trans;
+	int offset;
+
+	old_trans = ctx->trans0;
+	new_trans = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans, 
+			"db_context->trans (expand)", db_trans_st);
+	if (!new_trans)
+		goto out;
+	memcpy(new_trans, old_trans, ctx->max_trans * sizeof(struct db_trans));
+	
+	/* update trans0 (obviously) */
+	ctx->trans0 = ctx->prop.trans = new_trans;
+	/* update trans_cur (by offset) */
+	offset = (char *)(new_trans) - (char *)(old_trans);
+	(char *)(ctx->trans_cur) += offset;
+	/* update elem count */
+	ctx->max_trans = max_trans;
+	PFREE_ST(old_trans, db_trans_st);
+	ret = 0;
+out:
+	return ret;
+}
+/*	
+ *	Expand storage for attributes by delta_attrs number AND
+ *	rewrite trans->attr pointers
+ */
+static int
+db_attrs_expand(struct db_context *ctx, int delta_attrs)
+{
+	int ret = -1;
+	struct db_attr *new_attrs, *old_attrs;
+	struct db_trans *t;
+	int ti;
+	int max_attrs = ctx->max_attrs + delta_attrs;
+	int offset;
+
+	old_attrs = ctx->attrs0;
+	new_attrs = ALLOC_BYTES_ST ( sizeof (struct db_attr) * max_attrs, 
+			"db_context->attrs (expand)", db_attrs_st);
+	if (!new_attrs)
+		goto out;
+
+	memcpy(new_attrs, old_attrs, ctx->max_attrs * sizeof(struct db_attr));
+	
+	/* update attrs0 and attrs_cur (obviously) */
+	offset = (char *)(new_attrs) - (char *)(old_attrs);
+	(char *)ctx->attrs0 += offset;
+	(char *)ctx->attrs_cur += offset;
+	/* for each transform, rewrite attrs pointer by offsetting it */
+	for (t=ctx->prop.trans, ti=0; ti < ctx->prop.trans_cnt; t++, ti++) {
+		(char *)(t->attrs) += offset;
+	}
+	/* update elem count */
+	ctx->max_attrs = max_attrs;
+	PFREE_ST(old_attrs, db_attrs_st);
+	ret = 0;
+out:
+	return ret;
+}
+/*	Allocate a new db object */
+struct db_context * 
+db_prop_new(u_int8_t protoid, int max_trans, int max_attrs) 
+{
+	struct db_context *ctx;
+	ctx = ALLOC_BYTES_ST ( sizeof (struct db_context), "db_context", db_context_st);
+	if (!ctx) goto out;
+	
+	if (db_prop_init(ctx, protoid, max_trans, max_attrs) < 0) {
+		PFREE_ST(ctx, db_context_st);
+		ctx=NULL;
+	}
+out:
+	return ctx;
+}
+/*	Free a db object */
+void
+db_destroy(struct db_context *ctx)
+{
+	PFREE_ST(ctx->trans0, db_trans_st);
+	PFREE_ST(ctx->attrs0, db_attrs_st);
+	PFREE_ST(ctx, db_context_st);
+}
+/*	Start a new transform, expand trans0 is needed */
+int
+db_trans_add(struct db_context *ctx, u_int8_t transid)
+{
+	/*	skip incrementing current trans pointer the 1st time*/
+	if (ctx->trans_cur && ctx->trans_cur->attr_cnt)
+		ctx->trans_cur++;
+	/*	
+	 *	Strategy: if more space is needed, expand by 
+	 *	          <current_size>/2 + 1
+	 *
+	 *	This happens to produce a "reasonable" sequence
+	 *	after few allocations, eg.:
+	 *	0,1,2,4,8,13,20,31,47
+	 */
+	if ((ctx->trans_cur - ctx->trans0) >= ctx->max_trans) {
+		/* XXX:jjo if fails should shout and flag it */
+		if (db_trans_expand(ctx, ctx->max_trans/2 + 1)<0)
+			return -1;
+	}
+	ctx->trans_cur->transid = transid;
+	ctx->trans_cur->attrs=ctx->attrs_cur;
+	ctx->trans_cur->attr_cnt = 0;
+	ctx->prop.trans_cnt++;
+	return 0;
+}
+/*	Add attr copy to current transform, expanding attrs0 if needed */
+int
+db_attr_add(struct db_context *ctx, const struct db_attr *a) 
+{
+	/*	
+	 *	Strategy: if more space is needed, expand by 
+	 *	          <current_size>/2 + 1
+	 */
+	if ((ctx->attrs_cur - ctx->attrs0) >= ctx->max_attrs) {
+		/* XXX:jjo if fails should shout and flag it */
+		if (db_attrs_expand(ctx, ctx->max_attrs/2 + 1) < 0)
+			return -1;
+	}
+	*ctx->attrs_cur++=*a;
+	ctx->trans_cur->attr_cnt++;
+	return 0;
+}
+/*	Add attr copy (by value) to current transform, 
+ *	expanding attrs0 if needed, just calls db_attr_add().
+ */
+int
+db_attr_add_values(struct db_context *ctx,  u_int16_t type, u_int16_t val)
+{
+	struct db_attr attr;
+	attr.type = type;
+	attr.val = val;
+	return db_attr_add (ctx, &attr);
+}
+#ifndef NO_DB_OPS_STATS
+int
+db_ops_show_status(void)
+{
+	whack_log(RC_COMMENT, "stats " __FILE__ ": " 
+			DB_OPS_STATS_DESC " :"
+			DB_OPS_STATS_STR("context")
+			DB_OPS_STATS_STR("trans")
+			DB_OPS_STATS_STR("attrs"),
+			DB_OPS_STATS_F(db_context_st),
+			DB_OPS_STATS_F(db_trans_st),
+			DB_OPS_STATS_F(db_attrs_st)
+			);
+	return 0;
+}
+#endif /* NO_DB_OPS_STATS */
+/* 
+ * From below to end just testing stuff ....
+ */
+#ifdef TEST
+static void db_prop_print(struct db_prop *p)
+{
+	struct db_trans *t;
+	struct db_attr *a;
+	int ti, ai;
+	enum_names *n, *n_at, *n_av;
+	printf("protoid=\"%s\"\n", enum_name(&protocol_names, p->protoid));
+	for (ti=0, t=p->trans; ti< p->trans_cnt; ti++, t++) {
+		switch( t->transid) {
+			case PROTO_ISAKMP:
+				n=&isakmp_transformid_names;break;
+			case PROTO_IPSEC_ESP:
+				n=&esp_transformid_names;break;
+			default:
+				continue;
+		}
+		printf("  transid=\"%s\"\n", 
+			enum_name(n, t->transid));
+		for (ai=0, a=t->attrs; ai < t->attr_cnt; ai++, a++) {
+			int i;
+			switch( t->transid) {
+				case PROTO_ISAKMP:
+					n_at=&oakley_attr_names;
+					i=a->type|ISAKMP_ATTR_AF_TV;
+					n_av=oakley_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK];
+					break;
+				case PROTO_IPSEC_ESP:
+					n_at=&ipsec_attr_names;
+					i=a->type|ISAKMP_ATTR_AF_TV;
+					n_av=ipsec_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK];
+					break;
+				default:
+					continue;
+			}
+			printf("    type=\"%s\" value=\"%s\"\n", 
+				enum_name(n_at, i),
+				enum_name(n_av, a->val));
+		}
+	}
+
+}
+static void db_print(struct db_context *ctx) 
+{
+	printf("trans_cur diff=%d, attrs_cur diff=%d\n", 
+			ctx->trans_cur - ctx->trans0,
+			ctx->attrs_cur - ctx->attrs0);
+	db_prop_print(&ctx->prop);
+}
+
+void
+passert_fail(const char *pred_str, const char *file_str, unsigned long line_no);
+void abort(void);
+void
+passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
+{
+    fprintf(stderr, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
+    abort();	/* exiting correctly doesn't always work */
+}
+int main(void) {
+	struct db_context *ctx=db_prop_new(PROTO_ISAKMP, 0, 0);
+	db_trans_add(ctx, KEY_IKE);
+	db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC);
+	db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
+	db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG);
+	db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024);
+	db_trans_add(ctx, KEY_IKE);
+	db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_AES_CBC);
+	db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
+	db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY);
+	db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536);
+	db_trans_add(ctx, ESP_3DES);
+	db_attr_add_values(ctx, AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1);
+	db_print(ctx);
+	db_destroy(ctx);
+	return 0;
+}
+#endif
Index: freeswan/pluto/db_ops.h
diff -u /dev/null freeswan/pluto/db_ops.h:1.1.4.3
--- /dev/null	Fri Jul 12 16:03:46 2002
+++ freeswan/pluto/db_ops.h	Mon Jul  8 09:05:40 2002
@@ -0,0 +1,40 @@
+/*	$Id: db_ops.h,v 1.1.4.3 2002/07/08 12:05:40 jjo Exp $	*/
+#ifndef _DB_OPS_H
+#define _DB_OPS_H
+/*
+ * 	Main db object, (quite proposal "oriented")
+ */
+#ifndef NO_DB_CONTEXT
+struct db_context {
+	struct db_prop prop;		/* proposal buffer (not pointer) */
+	struct db_trans *trans0;	/* transf. list, dynamically sized */
+	struct db_trans *trans_cur;	/* current transform ptr */
+	struct db_attr *attrs0;		/* attr. list, dynamically sized */
+	struct db_attr *attrs_cur;	/* current attribute ptr */
+	int max_trans;			/* size of trans list */
+	int max_attrs;			/* size of attrs list */
+};
+/*
+ * 	Allocate a new db object
+ */
+struct db_context * db_prop_new(u_int8_t protoid, int max_trans, int max_attrs);
+/*	Initialize object for proposal building  */
+int db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs);
+/*	Free all resourses for this db */
+void db_destroy(struct db_context *ctx);
+
+/*	Start a new transform */
+int db_trans_add(struct db_context *ctx, u_int8_t transid);
+/*	Add a new attribute by copying db_attr content */
+int db_attr_add(struct db_context *db_ctx, const struct db_attr *attr);
+/*	Add a new attribute by value */
+int db_attr_add_values(struct db_context *ctx,  u_int16_t type, u_int16_t val);
+
+/*	Get proposal from db object */
+static __inline__ struct db_prop *db_prop_get(struct db_context *ctx) {
+	return &ctx->prop;
+}
+/*	Show stats (allocation, etc) */
+#endif /* NO_DB_CONTEXT */
+int db_ops_show_status(void);
+#endif /* _DB_OPS_H */
Index: freeswan/pluto/ike_alg.c
diff -u /dev/null freeswan/pluto/ike_alg.c:1.1.4.6
--- /dev/null	Fri Jul 12 16:03:46 2002
+++ freeswan/pluto/ike_alg.c	Mon Jun  3 11:50:48 2002
@@ -0,0 +1,425 @@
+/*
+ * IKE modular algorithm handling interface
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ * 
+ * ike_alg.c,v 1.1.4.3 2002/05/30 03:26:08 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.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "sha1.h"
+#include "md5.h"
+#include "crypto.h"
+
+#include "state.h"
+#include "packet.h"
+#include "kernel.h"
+#include "log.h"
+#include "whack.h"
+#include "spdb.h"
+#include "alg_info.h"
+#include "ike_alg.h"
+#include "db_ops.h"
+#include "id.h"
+#include "x509.h"
+#include "connections.h"
+
+#define return_on(var, val) do { var=val;goto return_out; } while(0);
+
+/*
+ * 	Create an OAKLEY proposal based on alg_info and policy
+ */
+struct db_context *
+ike_alg_db_new(struct alg_info_ike *ai , lset_t policy)
+{
+	struct db_context *db_ctx = NULL;
+	struct ike_info *ike_info;
+	unsigned ealg, halg, modp, eklen=0;
+	struct encrypt_desc *enc_desc;
+	int i;
+
+	if (!ai) {
+		whack_log(RC_LOG_SERIOUS, "no IKE algorithms "
+				"for this connection "
+				"(check ike algorithm string)");
+		goto fail;
+	}
+	policy &= POLICY_ID_AUTH_MASK;
+	db_ctx = db_prop_new(PROTO_ISAKMP, 8, 8 * 5);
+	/* for each group */
+	ALG_INFO_IKE_FOREACH(ai, ike_info, i) {
+		ealg = ike_info->ike_ealg;
+		halg = ike_info->ike_halg;
+		modp = ike_info->ike_modp;
+		eklen= ike_info->ike_eklen;
+		if (!ike_alg_enc_present(ealg)) {
+			DBG_log(__FUNCTION__ "() "
+					"ike enc ealg=%d not present",
+					ealg);
+			continue;
+		}
+		if (!ike_alg_hash_present(halg)) {
+			DBG_log(__FUNCTION__ "() "
+					"ike hash halg=%d not present",
+					halg);
+			continue;
+		}
+		enc_desc = ike_alg_get_encrypter(ealg);
+		passert(enc_desc != NULL);
+		if (eklen 
+		/*
+			&& eklen != enc_desc->keydeflen)
+		*/
+			&& (eklen < enc_desc->keyminlen
+				|| eklen >  enc_desc->keymaxlen))
+				
+		{
+			DBG_log(__FUNCTION__ "() "
+					"ealg=%d (specified) keylen:%d, "
+					"not valid "
+					/*
+					 "keylen != %d"
+					 */
+					"min=%d, max=%d"
+					, ealg
+					, eklen
+					/*
+					, enc_desc->keydeflen
+					*/
+					, enc_desc->keyminlen
+					, enc_desc->keymaxlen
+					);
+			continue;
+		}
+		if (policy & POLICY_RSASIG) {
+			db_trans_add(db_ctx, KEY_IKE);
+			db_attr_add_values(db_ctx, 
+					OAKLEY_ENCRYPTION_ALGORITHM, ealg);
+			db_attr_add_values(db_ctx, 
+					OAKLEY_HASH_ALGORITHM, halg);
+			if (eklen)
+				db_attr_add_values(db_ctx, 
+						OAKLEY_KEY_LENGTH, eklen);
+			db_attr_add_values(db_ctx, 
+					OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG);
+			db_attr_add_values(db_ctx, 
+					OAKLEY_GROUP_DESCRIPTION, modp);
+		}
+		if (policy & POLICY_PSK) {
+			db_trans_add(db_ctx, KEY_IKE);
+			db_attr_add_values(db_ctx, 
+					OAKLEY_ENCRYPTION_ALGORITHM, ealg);
+			db_attr_add_values(db_ctx, 
+					OAKLEY_HASH_ALGORITHM, halg);
+			if (ike_info->ike_eklen) 
+				db_attr_add_values(db_ctx, 
+						OAKLEY_KEY_LENGTH, ike_info->ike_eklen);
+			db_attr_add_values(db_ctx, 
+					OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY);
+			db_attr_add_values(db_ctx, 
+					OAKLEY_GROUP_DESCRIPTION, modp);
+		}
+	}
+fail:
+	return db_ctx;
+}
+/*
+ * 	Show registered IKE algorithms
+ */
+void
+ike_alg_show_status(void)
+{
+	unsigned alg, i;
+	struct ike_alg *algo;
+	IKE_EALG_FOR_EACH(algo) {
+		passert(algo != NULL);
+		alg=algo->algo_id;
+		whack_log(RC_COMMENT, "algorithm IKE encrypt: id=%d, name=%s, blocksize=%d, keydeflen=%d"
+			, alg
+			, enum_name(&oakley_enc_names, alg)
+			, ((struct encrypt_desc *)algo)->enc_blocksize
+			, ((struct encrypt_desc *)algo)->keydeflen
+			);
+		
+	}
+	IKE_HALG_FOR_EACH(algo) {
+		whack_log(RC_COMMENT, "algorithm IKE hash: id=%d, name=%s, hashsize=%d"
+			, algo->algo_id
+			, enum_name(&oakley_hash_names, algo->algo_id)
+			, ((struct hash_desc *)algo)->hash_digest_size
+			);
+	}
+#define IKE_DH_ALG_FOR_EACH(idx) for(idx = 0; idx != elemsof(oakley_group); idx++)
+	IKE_DH_ALG_FOR_EACH(i) {
+		const struct oakley_group_desc *gdesc=oakley_group+i;
+		whack_log(RC_COMMENT, "algorithm IKE dh group: id=%d, name=%s, bits=%d"
+			, gdesc->group
+			, enum_name(&oakley_group_names, gdesc->group)
+			, gdesc->bytes*BITS_PER_BYTE
+			);
+	}
+}
+/*
+ * 	Show IKE algorithms for 
+ * 	- this connection (result from ike= string)
+ * 	- newest SA
+ */
+void
+ike_alg_show_connection(struct connection *c, const char *instance)
+{
+	char buf[256];
+	struct state *st;
+	if (c->alg_info_ike) {
+		alg_info_snprint(buf, sizeof(buf), 
+				(struct alg_info *)c->alg_info_ike);
+		whack_log(RC_COMMENT
+		    , "\"%s\"%s:   IKE algorithms wanted: %s"
+		    , c->name
+		    , instance
+		    , buf);
+	}
+	if (c->alg_info_ike) {
+		alg_info_snprint_ike(buf, sizeof(buf), c->alg_info_ike);
+		whack_log(RC_COMMENT
+		    , "\"%s\"%s:   IKE algorithms found:  %s"
+		    , c->name
+		    , instance
+		    , buf);
+	}
+	st = state_with_serialno(c->newest_isakmp_sa);
+	if (st)
+		whack_log(RC_COMMENT
+		, "\"%s\"%s:   IKE algorithm newest: %s_%d-%s-%s"
+		, c->name
+		, instance
+		, enum_show(&oakley_enc_names, st->st_oakley.encrypt)
+		+7 /* strlen("OAKLEY_") */
+		/* , st->st_oakley.encrypter->keydeflen */
+		, st->st_oakley.enckeylen
+		, enum_show(&oakley_hash_names, st->st_oakley.hash)
+		+7 /* strlen("OAKLEY_") */
+		, enum_show(&oakley_group_names, st->st_oakley.group->group)
+		+13 /* strlen("OAKLEY_GROUP_") */
+	 );
+}
+/*==========================================================
+ *
+ * 	IKE algo list handling
+ *
+ * 	- registration
+ * 	- lookup
+ *=========================================================*/
+struct ike_alg *ike_alg_base[IKE_ALG_MAX+1] = {NULL, NULL};
+/*	check if IKE encrypt algo is present */
+bool ike_alg_enc_present(int ealg)
+{
+	struct encrypt_desc *enc_desc = ike_alg_get_encrypter(ealg);
+	return enc_desc ? enc_desc->enc_blocksize : 0;
+}
+/*	check if IKE hash algo is present */
+bool ike_alg_hash_present(int halg)
+{
+	struct hash_desc *hash_desc = ike_alg_get_hasher(halg);
+	return hash_desc ? hash_desc->hash_digest_size : 0;
+}
+bool ike_alg_enc_ok(int ealg, unsigned key_len, struct alg_info_ike *alg_info_ike, const char **errp)
+{
+	int ret=TRUE;
+	struct encrypt_desc *enc_desc;
+	char errbuf[256]="encrypt algo not found";
+	/* 
+	 * test #1: encrypt algo must be present 
+	 */
+	enc_desc = ike_alg_get_encrypter(ealg);
+	if (!enc_desc) return_on(ret, FALSE);
+	/* 
+	 * test #2: if key_len specified, it must be in range 
+	 */
+	if ((key_len) && ((key_len < enc_desc->keyminlen) ||
+			 (key_len > enc_desc->keymaxlen))) {
+		snprintf(errbuf, sizeof(errbuf),
+				"key_len not in range: encalg=%d, "
+				"key_len=%d, keyminlen=%d, keymaxlen=%d",
+				ealg, key_len,
+				enc_desc->keyminlen,
+				enc_desc->keymaxlen
+		       );
+		log (__FUNCTION__ "(): %s", errbuf);
+		return_on(ret, FALSE);
+	} 
+	/* 
+	 * test #3: if alg_info specified AND strict flag, only
+	 * only allow algo iff listed in st->alg_info_esp
+	 */
+	else if (alg_info_ike && (alg_info_ike->alg_info_flags & ALG_INFO_F_STRICT) ) {
+		int i;
+		struct ike_info *ike_info;
+		ALG_INFO_IKE_FOREACH(alg_info_ike, ike_info, i) {
+			if ((ike_info->ike_ealg == ealg) &&
+				((ike_info->ike_eklen==0) || (key_len==0) ||
+				 (ike_info->ike_eklen==key_len))) {
+				return_on(ret, TRUE);
+			}
+		}
+		snprintf(errbuf, sizeof(errbuf),
+				"strict flag and encrypt algorithm "
+				"not in transform string list: "
+				"ealg=%d, "
+				"key_len=%d, keyminbits=%d, keymaxbits=%d",
+				ealg, key_len,
+				enc_desc->keyminlen,
+				enc_desc->keymaxlen
+		   );
+		log(__FUNCTION__ "(): %s", errbuf);
+		return_on(ret, FALSE);
+	}
+return_out:
+	DBG(DBG_KLIPS, 
+		if (ret) 
+			DBG_log(__FUNCTION__ "(ealg=%d,key_len=%d): "
+				"blocksize=%d, keyminlen=%d, "
+				"keydeflen=%d, keymaxlen=%d, "
+				"ret=%d",
+				ealg, key_len,
+				enc_desc->enc_blocksize,
+				enc_desc->keyminlen,
+				enc_desc->keydeflen,
+				enc_desc->keymaxlen,
+				ret);
+		else 
+			DBG_log(__FUNCTION__ "(ealg=%d,key_len=%d): NO",
+				ealg, key_len);
+	);
+	if (!ret && *errp)
+		*errp=errbuf;
+	return ret;
+}
+/*
+ * 	return ike_algo object by {type, id}
+ */
+/* XXX:jjo use keysize */
+struct ike_alg *
+ike_alg_find(unsigned algo_type, unsigned algo_id, unsigned keysize __attribute__((unused)))
+{
+	struct ike_alg *e=ike_alg_base[algo_type];
+	for(;e!=NULL;e=e->algo_next) {
+		if (e->algo_id==algo_id)
+			break;
+	}
+	return e;
+}
+
+/*
+ * 	Main "raw" ike_alg list adding function
+ */
+int
+ike_alg_add(struct ike_alg* a)
+{
+	int ret=0;
+	const char *ugh="No error";
+	if (a->algo_type > IKE_ALG_MAX)
+	{
+		ugh="Invalid algo_type";
+		return_on(ret,-EINVAL);
+	}
+	if (ike_alg_find(a->algo_type, a->algo_id, 0))
+	{
+		ugh="Algorithm already exists";
+		return_on(ret,-EEXIST);
+	}
+	if (ret==0) {
+		a->algo_next=ike_alg_base[a->algo_type];
+		ike_alg_base[a->algo_type]=a;
+	}
+return_out:
+	if (ret) 
+		log(__FUNCTION__ "(): ERROR: %s", ugh);
+	return ret;
+}
+
+/*
+ * 	Validate and register IKE hash algorithm object
+ */
+int
+ike_alg_register_hash(struct hash_desc *hash_desc)
+{
+	const char *alg_name;
+	int ret=0;
+	if (hash_desc->algo_id > OAKLEY_HASH_MAX) {
+		log (__FUNCTION__ "(): hash alg=%d < max=%d",
+				hash_desc->algo_id, OAKLEY_HASH_MAX);
+		return_on(ret,-EINVAL);
+	}
+	if (hash_desc->hash_ctx_size > sizeof (union hash_ctx)) {
+		log (__FUNCTION__ "(): hash alg=%d has "
+				"ctx_size=%d > hash_ctx=%d",
+				hash_desc->algo_id, 
+				hash_desc->hash_ctx_size,
+				sizeof (union hash_ctx));
+		return_on(ret,-EOVERFLOW);
+	}
+	if (!(hash_desc->hash_init&&hash_desc->hash_update&&hash_desc->hash_final)) {
+		log (__FUNCTION__ "(): hash alg=%d needs  "
+				"hash_init(), hash_update() and hash_final()",
+				hash_desc->algo_id);
+		return_on(ret,-EINVAL);
+	}
+	alg_name=enum_name(&oakley_hash_names, hash_desc->algo_id);
+	if (!alg_name) {
+		log (__FUNCTION__ "(): WARNING: hash alg=%d not found in "
+				"constants.c:oakley_hash_names  ",
+				hash_desc->algo_id);
+		alg_name="<NULL>";
+	}
+
+return_out:
+	if (ret==0)
+		ret=ike_alg_add((struct ike_alg *)hash_desc);
+	log(__FUNCTION__ ": Activating %s: %s (ret=%d)", 
+			alg_name, ret==0? "Ok" : "FAILED", ret);
+	return ret;
+}
+
+/*
+ * 	Validate and register IKE encryption algorithm object
+ */
+int
+ike_alg_register_enc(struct encrypt_desc *enc_desc)
+{
+	const char *alg_name;
+	int ret=0;
+	if (enc_desc->algo_id > OAKLEY_ENCRYPT_MAX) {
+		log (__FUNCTION__ "(): enc alg=%d < max=%d\n",
+				enc_desc->algo_id, OAKLEY_ENCRYPT_MAX);
+		return_on(ret, -EINVAL);
+	}
+	alg_name=enum_name(&oakley_enc_names, enc_desc->algo_id);
+	if (!alg_name) {
+		log (__FUNCTION__ "(): WARNING: enc alg=%d not found in "
+				"constants.c:oakley_enc_names  ",
+				enc_desc->algo_id);
+		alg_name="<NULL>";
+	}
+return_out:
+	if (ret==0)
+		ret=ike_alg_add((struct ike_alg *)enc_desc);
+	log(__FUNCTION__ ": Activating %s: %s (ret=%d)", 
+			alg_name, ret==0? "Ok" : "FAILED", ret);
+	return 0;
+}
Index: freeswan/pluto/ike_alg.h
diff -u /dev/null freeswan/pluto/ike_alg.h:1.1.4.3
--- /dev/null	Fri Jul 12 16:03:46 2002
+++ freeswan/pluto/ike_alg.h	Mon Jun  3 11:50:48 2002
@@ -0,0 +1,63 @@
+#ifndef _IKE_ALG_H
+#define _IKE_ALG_H
+
+#define IKE_ALG_COMMON \
+	u_int16_t algo_type;		\
+	u_int16_t algo_id;		\
+	struct ike_alg *algo_next
+struct ike_alg {
+    IKE_ALG_COMMON;
+};
+struct encrypt_desc {
+    IKE_ALG_COMMON;
+    size_t enc_ctxsize;
+    size_t enc_blocksize;
+    unsigned keydeflen;
+    unsigned keymaxlen;
+    unsigned keyminlen;
+    void (*do_crypt)(u_int8_t *dat, size_t datasize, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc);
+};
+struct hash_desc {
+    IKE_ALG_COMMON;
+    size_t hash_ctx_size;
+    size_t hash_digest_size;
+    void (*hash_init)(void *ctx);
+    void (*hash_update)(void *ctx, const u_int8_t *in, size_t datasize);
+    void (*hash_final)(u_int8_t *out, void *ctx);
+};
+struct db_context * ike_alg_db_new(struct alg_info_ike *ai, lset_t policy);
+void ike_alg_show_status(void);
+void ike_alg_show_connection(struct connection *c, const char *instance);
+
+#define IKE_EALG_FOR_EACH(a) \
+	for(a=ike_alg_base[IKE_ALG_ENCRYPT];a;a=a->algo_next)
+#define IKE_HALG_FOR_EACH(a) \
+	for(a=ike_alg_base[IKE_ALG_HASH];a;a=a->algo_next)
+bool ike_alg_enc_present(int ealg);
+bool ike_alg_hash_present(int halg);
+bool ike_alg_enc_ok(int ealg, unsigned key_len, struct alg_info_ike *alg_info_ike, const char **);
+
+int ike_alg_init(void);
+
+/*	
+ *	This could be just OAKLEY_XXXXXX_ALGORITHM, but it's
+ *	here with other name as a way to assure that the
+ *	algorithm hook type is supported (detected at compile time)
+ */
+#define IKE_ALG_ENCRYPT	0
+#define IKE_ALG_HASH	1
+#define IKE_ALG_MAX	1
+extern struct ike_alg *ike_alg_base[IKE_ALG_MAX+1];
+int ike_alg_add(struct ike_alg *);
+int ike_alg_register_enc(struct encrypt_desc *e);
+int ike_alg_register_hash(struct hash_desc *a);
+struct ike_alg *ike_alg_find(unsigned algo_type, unsigned algo_id, unsigned keysize);
+static __inline__ struct hash_desc *ike_alg_get_hasher(int alg)
+{
+	return (struct hash_desc *) ike_alg_find(IKE_ALG_HASH, alg, 0);
+}
+static __inline__ struct encrypt_desc *ike_alg_get_encrypter(int alg)
+{
+	return (struct encrypt_desc *) ike_alg_find(IKE_ALG_ENCRYPT, alg, 0);
+}
+#endif /* _IKE_ALG_H */
Index: freeswan/pluto/ipsec_doi.c
diff -u freeswan/pluto/ipsec_doi.c:1.1.1.1.6.3 freeswan/pluto/ipsec_doi.c:1.1.1.1.6.1.2.5
--- freeswan/pluto/ipsec_doi.c:1.1.1.1.6.3	Fri Jul  5 00:16:22 2002
+++ freeswan/pluto/ipsec_doi.c	Fri Jul  5 00:35:30 2002
@@ -25,6 +25,7 @@
 #include <arpa/inet.h>
 #include <resolv.h>
 #include <arpa/nameser.h>	/* missing from <resolv.h> on old systems */
+#include <sys/time.h>		/* for gettimeofday */
 
 #include <freeswan.h>
 
@@ -53,6 +54,9 @@
 #include "sha1.h"
 #include "md5.h"
 #include "crypto.h" /* requires sha1.h and md5.h */
+#include "ike_alg.h"
+#include "kernel_alg.h"
+#include "alg_info.h"
 
 static bool encrypt_message(pb_stream *pbs, struct state *st);	/* forward declaration */
 
@@ -86,7 +90,10 @@
 , const struct oakley_group_desc *group)
 {
     MP_INT mp_g, mp_shared;
+    struct timeval tv0, tv1;
+    unsigned long tv_diff;
 
+    gettimeofday(&tv0, NULL);
     passert(st->st_sec_in_use);
     n_to_mpz(&mp_g, g.ptr, g.len);
     mpz_init(&mp_shared);
@@ -95,6 +102,21 @@
     freeanychunk(st->st_shared);	/* happens in odd error cases */
     st->st_shared = mpz_to_n(&mp_shared, group->bytes);
     mpz_clear(&mp_shared);
+    gettimeofday(&tv1, NULL);
+    tv_diff=(tv1.tv_sec  - tv0.tv_sec) * 1000000 + (tv1.tv_usec - tv0.tv_usec);
+    DBG(DBG_CRYPT, 
+    	DBG_log(__FUNCTION__ "(): time elapsed (%s): %ld usec"
+		, enum_show(&oakley_group_names, st->st_oakley.group->group)
+		, tv_diff);
+       );
+    /* if took more than 200 msec ... */
+    if (tv_diff > 200000) {
+	loglog(RC_LOG_SERIOUS, "WARNING: " __FUNCTION__ "(): for %s took "
+			"%ld usec"
+		, enum_show(&oakley_group_names, st->st_oakley.group->group)
+		, tv_diff);
+    }
+
 #ifdef DODGE_DH_MISSING_ZERO_BUG
     if (st->st_shared.ptr[0] == 0)
 	loglog(RC_LOG_SERIOUS, "shared DH secret has leading zero -- triggers Pluto 1.0 bug");
@@ -398,7 +420,7 @@
 	if (!out_generic(ISAKMP_NEXT_D, &isakmp_hash_desc, &r_hdr_pbs, &hash_pbs))
 	    impossible();
 	r_hashval = hash_pbs.cur;	/* remember where to plant value */
-	if (!out_zero(p1st->st_oakley.hasher->hash_digest_len, &hash_pbs, "HASH(1)"))
+	if (!out_zero(p1st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH(1)"))
 	    impossible();
 	close_output_pbs(&hash_pbs);
 	r_hash_start = r_hdr_pbs.cur;	/* hash from after HASH(1) */
@@ -432,7 +454,7 @@
 
 	DBG(DBG_CRYPT,
 	    DBG_log("HASH(1) computed:");
-	    DBG_dump("", r_hashval, ctx.hmac_digest_len);
+	    DBG_dump("", r_hashval, ctx.hmac_digest_size);
 	)
     }
 
@@ -804,9 +826,13 @@
 	union hash_ctx hash_ctx;
 	const struct hash_desc *h = st->st_oakley.hasher;
 
-	st->st_new_iv_len = h->hash_digest_len;
+	st->st_new_iv_len = h->hash_digest_size;
 	passert(st->st_new_iv_len <= sizeof(st->st_new_iv));
 
+        DBG(DBG_CRYPT,
+            DBG_dump_chunk("DH_i:", st->st_gi);
+            DBG_dump_chunk("DH_r:", st->st_gr);
+        );
 	h->hash_init(&hash_ctx);
 	h->hash_update(&hash_ctx, st->st_gi.ptr, st->st_gi.len);
 	h->hash_update(&hash_ctx, st->st_gr.ptr, st->st_gr.len);
@@ -819,7 +845,8 @@
      * See draft-ietf-ipsec-isakmp-oakley-07.txt Appendix B
      */
     {
-	const size_t keysize = st->st_oakley.encrypter->keysize;
+	/* const size_t keysize = st->st_oakley.encrypter->keydeflen/BITS_PER_BYTE; */
+	const size_t keysize = st->st_oakley.enckeylen/BITS_PER_BYTE;
 	u_char keytemp[MAX_OAKLEY_KEY_LEN + MAX_DIGEST_LEN];
 	u_char *k = st->st_skeyid_e.ptr;
 
@@ -833,11 +860,11 @@
 	    for (;;)
 	    {
 		hmac_final(&keytemp[i], &ctx);
-		i += ctx.hmac_digest_len;
+		i += ctx.hmac_digest_size;
 		if (i >= keysize)
 		    break;
 		hmac_reinit(&ctx);
-		hmac_update(&ctx, &keytemp[i - ctx.hmac_digest_len], ctx.hmac_digest_len);
+		hmac_update(&ctx, &keytemp[i - ctx.hmac_digest_size], ctx.hmac_digest_size);
 	    }
 	    k = keytemp;
 	}
@@ -927,9 +954,11 @@
     struct hmac_ctx ctx;
 
     hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid);
-    main_mode_hash_body(st, hashi, idpl, &ctx.hash_ctx, ctx.h->hash_update);
+    main_mode_hash_body(st, hashi, idpl, &ctx.hash_ctx, 
+	(void (*)(union hash_ctx *, const u_char *input, unsigned int len))
+		    ctx.h->hash_update);
     hmac_final(hash_val, &ctx);
-    return ctx.hmac_digest_len;
+    return ctx.hmac_digest_size;
 }
 
 #if 0	/* only needed for DSS */
@@ -1400,7 +1429,7 @@
     if (!out_generic(np, &isakmp_hash_desc, &(rbody), &hash_pbs)) \
 	return STF_INTERNAL_ERROR; \
     r_hashval = hash_pbs.cur;	/* remember where to plant value */ \
-    if (!out_zero(st->st_oakley.hasher->hash_digest_len, &hash_pbs, "HASH")) \
+    if (!out_zero(st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH")) \
 	return STF_INTERNAL_ERROR; \
     close_output_pbs(&hash_pbs); \
     r_hash_start = (rbody).cur;	/* hash from after HASH payload */ \
@@ -1425,7 +1454,7 @@
      * struct isakmp_hdr in packet.h.
      */
     {
-	size_t padding = pad_up(enc_len, e->blocksize);
+	size_t padding = pad_up(enc_len, e->enc_blocksize);
 
 	if (padding != 0)
 	{
@@ -1437,7 +1466,8 @@
 
     DBG(DBG_CRYPT, DBG_log("encrypting using %s", enum_show(&oakley_enc_names, st->st_oakley.encrypt)));
 
-    e->crypt(TRUE, enc_start, enc_len, st);
+    /* e->crypt(TRUE, enc_start, enc_len, st); */
+    crypto_cbc_encrypt(e, TRUE, enc_start, enc_len, st);
 
     update_iv(st);
     DBG_cond_dump(DBG_CRYPT, "next IV:", st->st_iv, st->st_iv_len);
@@ -1473,8 +1503,8 @@
 
     DBG(DBG_CRYPT,
 	DBG_log("HASH(%d) computed:", hash2 + 1);
-	DBG_dump("", dest, ctx.hmac_digest_len));
-    return ctx.hmac_digest_len;
+	DBG_dump("", dest, ctx.hmac_digest_size));
+    return ctx.hmac_digest_size;
 #   undef hmac_update
 }
 
@@ -1495,8 +1525,8 @@
     hmac_update_chunk(&ctx, st->st_ni);
     hmac_update_chunk(&ctx, st->st_nr);
     hmac_final(dest, &ctx);
-    DBG_cond_dump(DBG_CRYPT, "HASH(3) computed:", dest, ctx.hmac_digest_len);
-    return ctx.hmac_digest_len;
+    DBG_cond_dump(DBG_CRYPT, "HASH(3) computed:", dest, ctx.hmac_digest_size);
+    return ctx.hmac_digest_size;
 }
 
 /* Compute Phase 2 IV.
@@ -1508,7 +1538,10 @@
     const struct hash_desc *h = st->st_oakley.hasher;
     union hash_ctx ctx;
 
-    st->st_new_iv_len = h->hash_digest_len;
+    DBG_cond_dump(DBG_CRYPT, "last Phase 1 IV:"
+	, st->st_iv, st->st_iv_len);
+
+    st->st_new_iv_len = h->hash_digest_size;
     passert(st->st_new_iv_len <= sizeof(st->st_new_iv));
 
     h->hash_init(&ctx);
@@ -1626,7 +1659,10 @@
      * since no negotiation is possible, we pick one that is
      * very likely supported.
      */
-    st->st_pfs_group = policy & POLICY_PFS? isakmp_sa->st_oakley.group : NULL;
+    if (st->st_connection->alg_info_esp && st->st_connection->alg_info_esp->esp_pfsgroup)
+	    st->st_pfs_group = lookup_group(st->st_connection->alg_info_esp->esp_pfsgroup);
+    if (!st->st_pfs_group)
+	    st->st_pfs_group = policy & POLICY_PFS? isakmp_sa->st_oakley.group : NULL;
 
     /* Emit SA payload based on a subset of the policy bits.
      * POLICY_COMPRESS is considered iff we can do IPcomp.
@@ -2177,10 +2213,29 @@
 		needed_len = DES_CBC_BLOCK_SIZE * 3;
 		break;
 	    default:
+#ifndef NO_KERNEL_ALG
+		if((needed_len=kernel_alg_esp_enc_keylen(pi->attrs.transid))>0) {
+			/* XXX: check key_len "coupling with kernel.c's */
+			if (pi->attrs.key_len) {
+				needed_len=pi->attrs.key_len/8;
+				DBG(DBG_PARSING, DBG_log("compute_proto_keymat:"
+						"key_len=%d from peer",
+						needed_len));
+			}
+			break;
+		}
+#endif
 		exit_log("transform %s not implemented yet",
 		    enum_show(&esp_transformid_names, pi->attrs.transid));
 	    }
-
+#ifndef NO_KERNEL_ALG
+	    DBG(DBG_PARSING, DBG_log("compute_proto_keymat:"
+				    "needed_len (after ESP enc)=%d",
+				    needed_len));
+	    if (kernel_alg_esp_auth_ok(pi->attrs.auth, NULL)) {
+		needed_len += kernel_alg_esp_auth_keylen(pi->attrs.auth);
+	    } else
+#endif
 	    switch (pi->attrs.auth)
 	    {
 	    case AUTH_ALGORITHM_NONE:
@@ -2196,6 +2251,9 @@
 		exit_log("AUTH algorithm %s not implemented yet",
 		    enum_show(&auth_alg_names, pi->attrs.auth));
 	    }
+	    DBG(DBG_PARSING, DBG_log("compute_proto_keymat:"
+				    "needed_len (after ESP auth)=%d",
+				    needed_len));
 	    break;
 
     case PROTO_IPSEC_AH:
@@ -2223,7 +2281,7 @@
 
     /* Allocate space for the keying material.
      * Although only needed_len bytes are desired, we
-     * must round up to a multiple of ctx.hmac_digest_len
+     * must round up to a multiple of ctx.hmac_digest_size
      * so that our buffer isn't overrun.
      */
     {
@@ -2234,7 +2292,7 @@
 	hmac_init_chunk(&ctx_me, st->st_oakley.hasher, st->st_skeyid_d);
 	ctx_peer = ctx_me;	/* duplicate initial conditions */
 
-	needed_space = needed_len + pad_up(needed_len, ctx_me.hmac_digest_len);
+	needed_space = needed_len + pad_up(needed_len, ctx_me.hmac_digest_size);
 	replace(pi->our_keymat, alloc_bytes(needed_space, "keymat in compute_keymat()"));
 	replace(pi->peer_keymat, alloc_bytes(needed_space, "peer_keymat in quick_inI1_outR1()"));
 
@@ -2261,7 +2319,7 @@
 	    hmac_final(pi->our_keymat + i, &ctx_me);
 	    hmac_final(pi->peer_keymat + i, &ctx_peer);
 
-	    i += ctx_me.hmac_digest_len;
+	    i += ctx_me.hmac_digest_size;
 	    if (i >= needed_space)
 		break;
 
@@ -2270,10 +2328,10 @@
 	    hmac_reinit(&ctx_me);
 	    hmac_reinit(&ctx_peer);
 
-	    hmac_update(&ctx_me, pi->our_keymat + i - ctx_me.hmac_digest_len,
-		ctx_me.hmac_digest_len);
-	    hmac_update(&ctx_peer, pi->peer_keymat + i - ctx_peer.hmac_digest_len,
-		ctx_peer.hmac_digest_len);
+	    hmac_update(&ctx_me, pi->our_keymat + i - ctx_me.hmac_digest_size,
+		ctx_me.hmac_digest_size);
+	    hmac_update(&ctx_peer, pi->peer_keymat + i - ctx_peer.hmac_digest_size,
+		ctx_peer.hmac_digest_size);
 	}
     }
 
Index: freeswan/pluto/kernel.c
diff -u freeswan/pluto/kernel.c:1.1.1.1.6.3 freeswan/pluto/kernel.c:1.1.1.1.6.1.2.3
--- freeswan/pluto/kernel.c:1.1.1.1.6.3	Fri Jul  5 00:16:22 2002
+++ freeswan/pluto/kernel.c	Fri Jul  5 00:35:30 2002
@@ -51,6 +51,8 @@
 #include "server.h"
 #include "whack.h"	/* for RC_LOG_SERIOUS */
 
+#include "alg_info.h"
+#include "kernel_alg.h"
 
 bool can_do_IPcomp = TRUE;  /* can system actually perform IPCOMP? */
 
@@ -356,8 +358,12 @@
 	    log("pfkey_get read PF_KEY message with length %d that doesn't equal sadb_msg_len %u * %d; ignoring message"
 		, len, (unsigned) buf->msg.sadb_msg_len, IPSEC_PFKEYv2_ALIGN);
 	}
+	/*	for now, unsolicited messages can be: 
+	 *	SADB_ACQUIRE, SADB_REGISTER 
+	 */
 	else if (!(buf->msg.sadb_msg_pid == (unsigned)pid
-	|| (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_ACQUIRE)))
+	|| (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_ACQUIRE)
+	|| (buf->msg.sadb_msg_type == SADB_REGISTER)))
 	{
 	    /* not for us: ignore */
 	    DBG(DBG_KLIPS,
@@ -430,6 +436,9 @@
     case SADB_SATYPE_AH:
 	break;
     case SADB_SATYPE_ESP:
+#ifndef NO_KERNEL_ALG
+	kernel_alg_register_pfkey(buf, sizeof (pfkey_buf));
+#endif
 	break;
     case SADB_X_SATYPE_COMP:
 	/* ??? There ought to be an extension to list the
@@ -1948,6 +1957,7 @@
 	ipsec_spi_t esp_spi = inbound? st->st_esp.our_spi : st->st_esp.attrs.spi;
 	u_char *esp_dst_keymat = inbound? st->st_esp.our_keymat : st->st_esp.peer_keymat;
 
+#if 0+MOVED_TO_alg_info_h
 	struct esp_info {
 	    u_int8_t transid;	/* negotiated ESP transform */
 	    u_int16_t auth;	/* negotiated AUTH */
@@ -1957,8 +1967,10 @@
 	    u_int8_t encryptalg;
 	    u_int8_t authalg;
 	};
+#endif
 
 	const struct esp_info *ei;
+	u_int16_t key_len;
 
 	static const struct esp_info esp_info[] = {
 	    { ESP_NULL, AUTH_ALGORITHM_HMAC_MD5,
@@ -1993,6 +2005,14 @@
 	{
 	    if (ei == &esp_info[elemsof(esp_info)])
 	    {
+		/* Check for additional kernel alg */
+#ifndef NO_KERNEL_ALG
+		if ((ei=kernel_alg_esp_info(st->st_esp.attrs.transid, 
+					st->st_esp.attrs.auth))!=NULL) {
+			break;
+		}
+#endif
+
 		/* note: enum_show may use a static buffer, so two
 		 * calls in one printf would be a mistake.
 		 * enum_name does the same job, without a static buffer,
@@ -2009,8 +2029,31 @@
 		break;
 	}
 
+	key_len = st->st_esp.attrs.key_len/8;
+	if (key_len) {
+		/* XXX: must change to check valid _range_ key_len */
+		if (key_len > ei->enckeylen) {
+			loglog(RC_LOG_SERIOUS, "ESP transform %s passed key_len=%d > %d",
+			enum_name(&esp_transformid_names, st->st_esp.attrs.transid),
+			key_len, ei->enckeylen);
+			goto fail;
+		}
+	} else {
+		key_len = ei->enckeylen;
+		/* Grrrrr.... f*cking 7 bits jurassic algos 
+		* 168 bits in kernel, need 192 bits for keymat_len */
+		if (ei->transid == ESP_3DES && key_len == 21) 
+			key_len = 24;
+
+	}
+
 	/* divide up keying material */
-	passert(st->st_esp.keymat_len == ei->enckeylen + ei->authkeylen);
+	DBG(DBG_KLIPS|DBG_CONTROL|DBG_PARSING, 
+		if(st->st_esp.keymat_len != key_len + ei->authkeylen)
+			DBG_log("keymat_len=%d key_len=%d authkeylen=%d",
+				st->st_esp.keymat_len, key_len, ei->authkeylen);
+	);
+	passert(st->st_esp.keymat_len == key_len + ei->authkeylen);
 
 	set_text_said(text_said, &dst, esp_spi, SA_ESP);
 
@@ -2032,12 +2075,12 @@
 	&& (ei->authkeylen == 0
 	    || pfkey_build(pfkey_key_build(&extensions[SADB_EXT_KEY_AUTH]
 		    , SADB_EXT_KEY_AUTH, ei->authkeylen * IPSEC_PFKEYv2_ALIGN
-		    , esp_dst_keymat + ei->enckeylen)
+		    , esp_dst_keymat + key_len)
 		, "pfkey_key_a Add ESP SA", text_said, extensions))
 
-	&& (ei->enckeylen == 0
+	&& (key_len == 0
 	    || pfkey_build(pfkey_key_build(&extensions[SADB_EXT_KEY_ENCRYPT]
-		    , SADB_EXT_KEY_ENCRYPT, ei->enckeylen * IPSEC_PFKEYv2_ALIGN
+		    , SADB_EXT_KEY_ENCRYPT, key_len * IPSEC_PFKEYv2_ALIGN
 		    , esp_dst_keymat)
 		, "pfkey_key_a Add ESP SA", text_said, extensions))
 
Index: freeswan/pluto/kernel_alg.c
diff -u /dev/null freeswan/pluto/kernel_alg.c:1.1.4.3
--- /dev/null	Fri Jul 12 16:03:47 2002
+++ freeswan/pluto/kernel_alg.c	Mon Jun  3 11:50:48 2002
@@ -0,0 +1,654 @@
+/*
+ * Kernel runtime algorithm handling interface
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ * 
+ * $Id: kernel_alg.c,v 1.1.4.3 2002/06/03 14:50:48 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.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "id.h"
+#include "x509.h"
+#include "connections.h"
+#include "state.h"
+#include "packet.h"
+#include "spdb.h"
+#include "kernel.h"
+#include "kernel_alg.h"
+#include "alg_info.h"
+
+#ifndef NO_PLUTO
+#include "log.h"
+#include "whack.h"
+#include "db_ops.h"
+#else
+/*
+ *	macros/functions for compilation without pluto (eg: spi for manual conns)
+ */
+extern int debug;
+#include <assert.h>
+#define passert(x) assert(x)
+#define DBG(cond, action)   { if (debug) { action ; } }
+#define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args);
+#define log(x, args...) fprintf(stderr, x "\n" , ##args);
+#endif /* NO_PLUTO */
+/* ALG storage */
+static struct sadb_alg esp_aalg[SADB_AALG_MAX+1];
+static struct sadb_alg esp_ealg[SADB_EALG_MAX+1];
+static int esp_ealg_num=0;
+static int esp_aalg_num=0;
+
+#define ESP_EALG_PRESENT(algo) (((algo)<=SADB_EALG_MAX)&&(esp_ealg[(algo)].sadb_alg_id==(algo)))
+#define ESP_EALG_FOR_EACH(algo) \
+	for (algo=1; algo <= SADB_EALG_MAX; algo++) \
+		if (ESP_EALG_PRESENT(algo))
+#define ESP_EALG_FOR_EACH_UPDOWN(algo) \
+	for (algo=SADB_EALG_MAX; algo >0 ; algo--) \
+		if (ESP_EALG_PRESENT(algo))
+#define ESP_AALG_PRESENT(algo) ((algo<=SADB_AALG_MAX)&&(esp_aalg[(algo)].sadb_alg_id==(algo)))
+#define ESP_AALG_FOR_EACH(algo) \
+	for (algo=1; algo <= SADB_AALG_MAX; algo++) \
+		if (ESP_AALG_PRESENT(algo))
+#define ESP_AALG_FOR_EACH_UPDOWN(algo) \
+	for (algo=SADB_AALG_MAX; algo >0 ; algo--) \
+		if (ESP_AALG_PRESENT(algo))
+
+static struct sadb_alg *
+sadb_alg_ptr (int satype, int exttype, int alg_id, int rw)
+{
+	struct sadb_alg *alg_p=NULL;
+	switch(exttype) {
+		case SADB_EXT_SUPPORTED_AUTH:
+			if (alg_id<=SADB_AALG_MAX)
+				break;
+			goto fail;		
+		case SADB_EXT_SUPPORTED_ENCRYPT:
+			if (alg_id<=SADB_EALG_MAX)
+				break;
+			goto fail;		
+		default:
+			goto fail;
+	}
+	switch(satype) {
+		case SADB_SATYPE_ESP:
+			alg_p=(exttype == SADB_EXT_SUPPORTED_ENCRYPT)? 
+				&esp_ealg[alg_id] : &esp_aalg[alg_id];
+			/* get for write: increment elem count */
+			if (rw) {
+				(exttype == SADB_EXT_SUPPORTED_ENCRYPT)?
+					esp_ealg_num++ : esp_aalg_num++;
+			}
+			break;
+		case SADB_SATYPE_AH:
+			goto fail;
+		default:
+			goto fail;
+	}
+fail:
+	return alg_p;
+}
+
+const struct sadb_alg *
+kernel_alg_sadb_alg_get(int satype, int exttype, int alg_id)
+{
+	return sadb_alg_ptr(satype, exttype, alg_id, 0);
+}
+/*
+ * 	Forget previous registration
+ */
+static void 
+kernel_alg_init(void)
+{
+	DBG(DBG_KLIPS, DBG_log("alg_init():"
+		"memset(%p, 0, %d) "
+		"memset(%p, 0, %d) ",
+		&esp_aalg,  sizeof (esp_aalg),
+		&esp_ealg,  sizeof (esp_ealg)));
+	memset (&esp_aalg, 0, sizeof (esp_aalg));
+	memset (&esp_ealg, 0, sizeof (esp_ealg));
+	esp_ealg_num=esp_aalg_num=0;
+}
+
+static int
+kernel_alg_add(int satype, int exttype, const struct sadb_alg *sadb_alg)
+{
+	int ret=-1;
+	struct sadb_alg *alg_p=NULL;
+	int alg_id=sadb_alg->sadb_alg_id;
+	DBG(DBG_KLIPS, DBG_log("kernel_alg_add():"
+		"satype=%d, exttype=%d, alg_id=%d",
+		satype, exttype, sadb_alg->sadb_alg_id));
+	if (!(alg_p=sadb_alg_ptr(satype, exttype, alg_id, 1)))
+		goto fail;
+
+	/*
+	DBG(DBG_KLIPS, DBG_log("kernel_alg_add(): assign *%p=*%p",
+			alg_p, sadb_alg));
+	*/
+	*alg_p=*sadb_alg;
+	ret=1;
+fail:
+	return ret;
+}
+
+bool
+kernel_alg_esp_enc_ok(int alg_id, unsigned int key_len, struct alg_info_esp *alg_info)
+{
+	struct sadb_alg *alg_p=NULL;
+	/* 
+	 * test #1: encrypt algo must be present 
+	 */
+	int ret=ESP_EALG_PRESENT(alg_id);
+	if (!ret) goto out;
+
+	alg_p=&esp_ealg[alg_id];
+	/* 
+	 * test #2: if key_len specified, it must be in range 
+	 */
+	if ((key_len) && ((key_len < alg_p->sadb_alg_minbits) ||
+			 (key_len > alg_p->sadb_alg_maxbits))) {
+		log (__FUNCTION__ "() key_len not in range: alg_id=%d, "
+				"key_len=%d, alg_minbits=%d, alg_maxbits=%d",
+				alg_id, key_len,
+				alg_p->sadb_alg_minbits,
+				alg_p->sadb_alg_maxbits
+		       );
+		ret = FALSE;
+	} 
+	/* 
+	 * test #3: if alg_info specified AND strict flag, only
+	 * only allow algo iff listed in st->alg_info_esp
+	 */
+	else if (alg_info && (alg_info->alg_info_flags & ALG_INFO_F_STRICT) ) {
+		int i;
+		struct esp_info *esp_info;
+		ALG_INFO_ESP_FOREACH(alg_info, esp_info, i) {
+			if ((esp_info->esp_ealg_id == alg_id) &&
+				((esp_info->esp_ealg_keylen==0) || (key_len==0) ||
+				 (esp_info->esp_ealg_keylen==key_len))) {
+				ret = TRUE;
+				goto out;
+			}
+		}
+		log(__FUNCTION__ "() strict flag and algo not in alg_info: "
+				"alg_id=%d, "
+				"key_len=%d, alg_minbits=%d, alg_maxbits=%d",
+				alg_id, key_len,
+				alg_p->sadb_alg_minbits,
+				alg_p->sadb_alg_maxbits
+		   );
+		ret = FALSE;
+	}
+out:
+	if (ret) {
+		DBG(DBG_KLIPS, 
+			DBG_log("kernel_alg_esp_enc_ok(%d,%d): "
+				"alg_id=%d, "
+				"alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
+				"res=%d, ret=%d",
+				alg_id, key_len,
+				alg_p->sadb_alg_id,
+				alg_p->sadb_alg_ivlen,
+				alg_p->sadb_alg_minbits,
+				alg_p->sadb_alg_maxbits,
+				alg_p->sadb_alg_reserved,
+				ret);
+		   );
+	} else {
+		DBG(DBG_KLIPS, 
+			DBG_log("kernel_alg_esp_enc_ok(%d,%d): NO",
+				alg_id, key_len);
+		);
+	}
+	return ret;
+}
+
+/*	
+ *	Load kernel_alg arrays from /proc
+ * 	used in manual mode from klips/utils/spi.c
+ */
+int
+kernel_alg_proc_read(void) {
+	int satype;
+	int supp_exttype;
+	int alg_id, ivlen, minbits, maxbits;
+	struct sadb_alg sadb_alg;
+	int ret;
+	char buf[128];
+	FILE *fp=fopen("/proc/net/pf_key_supported", "r");
+	if (!fp)
+		return -1;
+	kernel_alg_init();
+	while (fgets(buf, sizeof(buf), fp)) {
+		if (buf[0] != ' ') /* skip titles */
+			continue;
+		sscanf(buf, "%d %d %d %d %d %d",
+				&satype, &supp_exttype,
+				&alg_id, &ivlen,
+				&minbits, &maxbits
+				);
+		switch (satype) {
+			case SADB_SATYPE_ESP:
+				switch(supp_exttype) {
+					case SADB_EXT_SUPPORTED_AUTH:
+					case SADB_EXT_SUPPORTED_ENCRYPT:
+						sadb_alg.sadb_alg_id=alg_id;
+						sadb_alg.sadb_alg_ivlen=ivlen;
+						sadb_alg.sadb_alg_minbits=minbits;
+						sadb_alg.sadb_alg_maxbits=maxbits;
+						ret=kernel_alg_add(satype, supp_exttype, &sadb_alg);
+						DBG(DBG_CRYPT, DBG_log(__FUNCTION__ "() alg_id=%d, "
+							"alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
+							"ret=%d",
+							sadb_alg.sadb_alg_id,
+							sadb_alg.sadb_alg_ivlen,
+							sadb_alg.sadb_alg_minbits,
+							sadb_alg.sadb_alg_maxbits,
+							ret));
+				}
+			default: 
+				continue;
+		}
+	}
+	fclose(fp);
+	return 0;
+}
+
+/*	
+ *	Load kernel_alg arrays pluto's SADB_REGISTER	
+ * 	user by pluto/kernel.c
+ */
+
+void
+kernel_alg_register_pfkey(void *buf, int buflen)
+{
+	/*	
+	 *	Trick: one 'type-mangle-able' pointer to
+	 *	ease offset/assign 
+	 */
+	union {
+		const struct sadb_msg *msg;
+		const struct sadb_supported *supported;
+		const struct sadb_ext *ext;
+		const struct sadb_alg *alg;
+		const char *ch;
+	} sadb;
+	const struct sadb_msg *msg_buf=buf;
+	int satype;
+	int msglen;
+	int i=0;
+	/*	Initialize alg arrays 	*/
+	kernel_alg_init();
+	satype=msg_buf->sadb_msg_satype;
+	sadb.msg=msg_buf;
+	msglen=sadb.msg->sadb_msg_len*IPSEC_PFKEYv2_ALIGN;
+	msglen-=sizeof(struct sadb_msg);
+	buflen-=sizeof(struct sadb_msg);
+	passert(buflen>0);
+	sadb.msg++;
+	while(msglen) {
+		int supp_exttype=sadb.supported->sadb_supported_exttype;
+		int supp_len;
+		supp_len=sadb.supported->sadb_supported_len*IPSEC_PFKEYv2_ALIGN;
+		DBG(DBG_KLIPS, DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: "
+			"sadb_msg_len=%d sadb_supported_len=%d",
+			satype==SADB_SATYPE_ESP? "ESP" : "AH",
+			msg_buf->sadb_msg_len, 
+			supp_len));
+		sadb.supported++;
+		msglen-=supp_len;
+		buflen-=supp_len;
+		passert(buflen>=0);
+		for (supp_len-=sizeof(struct sadb_supported);
+			supp_len;
+			supp_len-=sizeof(struct sadb_alg), sadb.alg++,i++) {
+			int ret;
+			ret=kernel_alg_add(satype, supp_exttype, sadb.alg);
+			DBG(DBG_KLIPS, DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: "
+				"alg[%d], exttype=%d, satype=%d, alg_id=%d, "
+				"alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
+				"res=%d, ret=%d",
+				satype==SADB_SATYPE_ESP? "ESP" : "AH",
+				i,
+				supp_exttype,
+				satype,
+				sadb.alg->sadb_alg_id,
+				sadb.alg->sadb_alg_ivlen,
+				sadb.alg->sadb_alg_minbits,
+				sadb.alg->sadb_alg_maxbits,
+				sadb.alg->sadb_alg_reserved,
+				ret));
+		}
+	}
+}
+
+int
+kernel_alg_esp_enc_keylen(int alg_id)
+{
+	int keylen=0;
+	if (!ESP_EALG_PRESENT(alg_id))
+		goto none;
+	keylen=esp_ealg[alg_id].sadb_alg_maxbits/BITS_PER_BYTE;
+none:	
+	DBG(DBG_KLIPS, DBG_log("kernel_alg_esp_enc_keylen():"
+		"alg_id=%d, keylen=%d",
+		alg_id, keylen));
+	
+	return keylen;
+}
+
+struct sadb_alg *
+kernel_alg_esp_sadb_alg(int alg_id)
+{
+	struct sadb_alg *sadb_alg=NULL;
+	if (!ESP_EALG_PRESENT(alg_id))
+		goto none;
+	sadb_alg=&esp_ealg[alg_id];
+none:
+	DBG(DBG_KLIPS, DBG_log("kernel_alg_esp_sadb_alg():"
+		"alg_id=%d, sadb_alg=%p",
+		alg_id, sadb_alg));
+	return sadb_alg;
+}
+
+#ifndef NO_PLUTO
+void kernel_alg_show_status(void)
+{
+	unsigned sadb_id,id;
+	struct sadb_alg *alg_p;
+	ESP_EALG_FOR_EACH(sadb_id) {
+		id=sadb_id;
+		alg_p=&esp_ealg[sadb_id];
+		whack_log(RC_COMMENT, "algorithm ESP encrypt: id=%d, name=%s, "
+				"ivlen=%d, keysizemin=%d, keysizemax=%d"
+			, id
+			, enum_name(&esp_transformid_names, id)
+			, alg_p->sadb_alg_ivlen
+			, alg_p->sadb_alg_minbits
+			, alg_p->sadb_alg_maxbits
+		 );
+		
+	}
+	ESP_AALG_FOR_EACH(sadb_id) {
+		id=alg_info_esp_sadb2aa(sadb_id);
+		alg_p=&esp_aalg[sadb_id];
+		whack_log(RC_COMMENT, "algorithm ESP auth attr: id=%d, name=%s, "
+				"keysizemin=%d, keysizemax=%d"
+			, id
+			, enum_name(&auth_alg_names, id)
+			, alg_p->sadb_alg_minbits
+			, alg_p->sadb_alg_maxbits
+		 );
+	}
+}
+void
+kernel_alg_show_connection(struct connection *c, const char *instance)
+{
+	char buf[256];
+	struct state *st;
+	if (c->alg_info_esp) {
+		alg_info_snprint(buf, sizeof(buf), (struct alg_info *)c->alg_info_esp);
+		whack_log(RC_COMMENT
+		    , "\"%s\"%s:   ESP algorithms wanted: %s"
+		    , c->name
+		    , instance
+		    , buf);
+	}
+	if (c->alg_info_esp) {
+		alg_info_snprint_esp(buf, sizeof(buf), c->alg_info_esp);
+		whack_log(RC_COMMENT
+		    , "\"%s\"%s:   ESP algorithms loaded: %s"
+		    , c->name
+		    , instance
+		    , buf);
+	}
+	st = state_with_serialno(c->newest_ipsec_sa);
+	if (st && st->st_esp.present)
+		whack_log(RC_COMMENT
+		, "\"%s\"%s:   ESP algorithm newest: %s_%d-%s; pfsgroup=%s"
+		, c->name
+		, instance
+		, enum_show(&esp_transformid_names, st->st_esp.attrs.transid)
+		+4 /* strlen("ESP_") */
+		, st->st_esp.attrs.key_len
+		, enum_show(&auth_alg_names, st->st_esp.attrs.auth)+
+		+15 /* strlen("AUTH_ALGORITHM_") */
+		, c->policy & POLICY_PFS ?
+			c->alg_info_esp->esp_pfsgroup ?
+					enum_show(&oakley_group_names, 
+						c->alg_info_esp->esp_pfsgroup)
+						+13 /*strlen("OAKLEY_GROUP_")*/
+				: "<Phase1>"
+			: "<N/A>"
+	);
+}
+#endif /* NO_PLUTO */
+
+bool
+kernel_alg_esp_auth_ok(int auth, struct alg_info_esp *alg_info)
+{
+	int ret=(ESP_AALG_PRESENT(alg_info_esp_aa2sadb(auth)));
+	if (ret && alg_info && 
+		(alg_info->alg_info_flags & ALG_INFO_F_STRICT)) {
+		int i;
+		struct esp_info *esp_info;
+		ALG_INFO_ESP_FOREACH(alg_info, esp_info, i) {
+			if (esp_info->esp_aalg_id == auth) 
+				goto out;
+		}
+		ret = FALSE;
+	}
+	DBG(DBG_CONTROL | DBG_CRYPT | DBG_PARSING
+		    , DBG_log(__FUNCTION__ "(auth=%d): ret=%d",
+			    auth, ret));
+out:
+	return ret;
+}
+
+int
+kernel_alg_esp_auth_keylen(int auth)
+{
+	int sadb_aalg=alg_info_esp_aa2sadb(auth);
+	int a_keylen=0;
+	if (sadb_aalg)
+		a_keylen=esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE;
+
+	DBG(DBG_CONTROL | DBG_CRYPT | DBG_PARSING
+		    , DBG_log(__FUNCTION__ "(auth=%d, sadb_aalg=%d): "
+		    "a_keylen=%d", auth, sadb_aalg, a_keylen));
+	return a_keylen;
+}
+
+struct esp_info *
+kernel_alg_esp_info(int transid, int auth)
+{
+	int sadb_aalg, sadb_ealg;
+	static struct esp_info ei_buf;
+	sadb_ealg=transid;
+	sadb_aalg=alg_info_esp_aa2sadb(auth);
+
+	if (!ESP_EALG_PRESENT(sadb_ealg))
+		goto none;
+	if (!ESP_AALG_PRESENT(sadb_aalg))
+		goto none;
+	memset(&ei_buf, 0, sizeof (ei_buf));
+	ei_buf.transid=transid;
+	ei_buf.auth=auth;
+	ei_buf.enckeylen=esp_ealg[sadb_ealg].sadb_alg_maxbits/BITS_PER_BYTE;
+
+	ei_buf.authkeylen=esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE;
+	ei_buf.encryptalg=sadb_ealg;
+	ei_buf.authalg=sadb_aalg;
+	DBG(DBG_PARSING, DBG_log("kernel_alg_esp_info():"
+		"transid=%d, auth=%d, ei=%p, "
+		"enckeylen=%d, authkeylen=%d, encryptalg=%d, authalg=%d",
+		transid, auth, &ei_buf,
+		ei_buf.enckeylen, ei_buf.authkeylen,
+		ei_buf.encryptalg, ei_buf.authalg
+	       ));
+	return &ei_buf;		
+none:
+	DBG(DBG_PARSING, DBG_log("kernel_alg_esp_info():"
+		"transid=%d, auth=%d, ei=NULL",
+		transid, auth));
+	return NULL;
+}
+
+#ifndef NO_PLUTO
+static void
+kernel_alg_policy_algorithms(struct esp_info *esp_info)
+{
+    int ealg_i=esp_info->esp_ealg_id;
+    switch(ealg_i) {
+        case 0:
+        case ESP_3DES:
+        case ESP_NULL:
+        case ESP_CAST:
+            break;
+        default:
+            if (!esp_info->esp_ealg_keylen) {
+                /**
+                 * algos that need  KEY_LENGTH
+                 *
+                 * Note: this is a very dirty hack ;-)
+                 *
+                 * XXX:jjo
+                 * Idea: Add a key_length_needed attribute to 
+                 * esp_ealg ??
+                 */
+                esp_info->esp_ealg_keylen=
+                    esp_ealg[ealg_i].sadb_alg_maxbits;
+
+            }
+    }
+}
+static bool 
+kernel_alg_db_add(struct db_context *db_ctx, struct esp_info *esp_info, lset_t policy)
+{
+	int ealg_i, aalg_i;
+	ealg_i=esp_info->esp_ealg_id;
+	if (!ESP_EALG_PRESENT(ealg_i)) {
+		DBG_log(__FUNCTION__ "() "
+				"kernel enc ealg_id=%d not present",
+				ealg_i);
+		return FALSE;
+	}
+	if (!(policy & POLICY_AUTHENTICATE)) {	/* skip ESP auth attrs for AH */
+		aalg_i=alg_info_esp_aa2sadb(esp_info->esp_aalg_id);
+		if (!ESP_AALG_PRESENT(aalg_i)) {
+			DBG_log(__FUNCTION__ "() kernel auth "
+					"aalg_id=%d not present",
+					aalg_i);
+			return FALSE;
+		}
+	}
+	/* 	do algo policy */
+	kernel_alg_policy_algorithms(esp_info);
+
+	/*	open new transformation */
+	db_trans_add(db_ctx, ealg_i);
+	/* add ESP auth attr */
+	if (!(policy & POLICY_AUTHENTICATE)) 
+		db_attr_add_values(db_ctx, 
+				AUTH_ALGORITHM, esp_info->esp_aalg_id);
+	/*	add keylegth if specified in esp= string */
+	if (esp_info->esp_ealg_keylen) {
+		db_attr_add_values(db_ctx, 
+				KEY_LENGTH, esp_info->esp_ealg_keylen);
+	}
+	return TRUE;
+}
+/*	
+ *	Create proposal with runtime kernel algos, merging
+ *	with passed proposal if not NULL
+ *
+ *	for now this function does free() previous returned
+ *	malloced pointer (this quirk allows easier spdb.c change)
+ */
+struct db_context * 
+kernel_alg_db_new(struct alg_info_esp *alg_info, lset_t policy )
+{
+	int ealg_i, aalg_i, tn=0;
+	int i;
+	const struct esp_info *esp_info;
+	struct esp_info tmp_esp_info;
+	struct db_context *ctx_new=NULL;
+	struct db_trans *t;
+	struct db_prop  *prop;
+	int trans_cnt;
+
+	if (!(policy & POLICY_ENCRYPT))	{ /* not possible, I think  */
+		return NULL;
+	}
+	trans_cnt=(esp_ealg_num*esp_aalg_num);
+	DBG(DBG_EMITTING, DBG_log("kernel_alg_db_prop_new() "
+		"initial trans_cnt=%d",
+		trans_cnt));
+	/*	pass aprox. number of transforms and attributes */
+	ctx_new = db_prop_new(PROTO_IPSEC_ESP, trans_cnt, trans_cnt * 2);
+
+	/*
+	 * 	Loop: for each element (struct esp_info) of
+	 * 	alg_info, if kernel support is present then
+	 * 	build the transform (and attrs)
+	 *
+	 * 	if NULL alg_info, propose everything ...
+	 */
+
+	/* passert(alg_info!=0); */
+	if (alg_info) {
+		ALG_INFO_ESP_FOREACH(alg_info, esp_info, i) {
+			tmp_esp_info = *esp_info;
+			kernel_alg_db_add(ctx_new, &tmp_esp_info, policy);
+		}
+	} else {
+		ESP_EALG_FOR_EACH_UPDOWN(ealg_i) {
+			tmp_esp_info.esp_ealg_id=ealg_i;
+			tmp_esp_info.esp_ealg_keylen=0;
+			ESP_AALG_FOR_EACH(aalg_i) {
+				tmp_esp_info.esp_aalg_id=alg_info_esp_sadb2aa(aalg_i);
+				tmp_esp_info.esp_aalg_keylen=0;
+				kernel_alg_db_add(ctx_new, &tmp_esp_info, policy);
+			}
+		}
+	}
+
+	prop=db_prop_get(ctx_new);
+
+	DBG(DBG_CONTROL|DBG_EMITTING, DBG_log("kernel_alg_db_prop_new() "
+		"will return p_new->protoid=%d, p_new->trans_cnt=%d",
+		prop->protoid, prop->trans_cnt));
+	for(t=prop->trans,tn=0; tn<prop->trans_cnt; tn++) {
+		DBG(DBG_CONTROL|DBG_EMITTING, DBG_log("kernel_alg_db_prop_new() "
+			"    trans[%d]: transid=%d, attr_cnt=%d, "
+			"attrs[0].type=%d, attrs[0].val=%d",
+			tn,
+			t[tn].transid, t[tn].attr_cnt,
+			t[tn].attrs[0].type, t[tn].attrs[0].val
+			));
+	}
+	return ctx_new;
+}
+#endif /* NO_PLUTO */
Index: freeswan/pluto/kernel_alg.h
diff -u /dev/null freeswan/pluto/kernel_alg.h:1.1.4.2
--- /dev/null	Fri Jul 12 16:03:47 2002
+++ freeswan/pluto/kernel_alg.h	Thu May 30 00:26:08 2002
@@ -0,0 +1,53 @@
+/*
+ * Kernel runtime algorithm handling interface definitions
+ * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+ *
+ * $Id: kernel_alg.h,v 1.1.4.2 2002/05/30 03:26:08 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.
+ */
+
+#ifndef _KERNEL_ALG_H
+#define _KERNEL_ALG_H
+
+/* status info */
+extern void kernel_alg_show_status(void);
+void kernel_alg_show_connection(struct connection *c, const char *instance);
+
+/* Registration messages from pluto */
+extern void kernel_alg_register_pfkey(void *buf, int buflen);
+
+struct alg_info;
+struct esp_info;
+struct alg_info_ike;
+struct alg_info_esp;
+/* ESP interface */
+extern struct sadb_alg *kernel_alg_esp_sadb_alg(int alg_id);
+extern int kernel_alg_esp_ivlen(int alg_id);
+/* returns bool success if esp encrypt alg is present  */
+extern bool kernel_alg_esp_enc_ok(int alg_id, unsigned int key_len, struct alg_info_esp *nfo);
+/* returns encrypt keylen in BYTES for esp enc alg passed */
+extern int kernel_alg_esp_enc_keylen(int alg_id);
+/* returns bool success if esp auth alg is present  */
+extern bool kernel_alg_esp_auth_ok(int auth, struct alg_info_esp *nfo);
+/* returns auth keylen in BYTES for esp auth alg passed */
+extern int kernel_alg_esp_auth_keylen(int auth);
+/* returns 0 if read ok from /proc/net/pf_key_supported */
+extern int kernel_alg_proc_read(void);
+
+/* get sadb_alg for passed args */
+extern const struct sadb_alg * kernel_alg_sadb_alg_get(int satype, int exttype, int alg_id);
+
+struct db_prop;
+extern struct db_context * kernel_alg_db_new(struct alg_info_esp *ai, lset_t policy);
+/* returns pointer to static buffer, no reentrant */
+struct esp_info * kernel_alg_esp_info(int esp_id, int auth_id);
+#endif /* _KERNEL_ALG_H */
Index: freeswan/pluto/kernel_comm.c
diff -u freeswan/pluto/kernel_comm.c:1.1.1.1.6.2 freeswan/pluto/kernel_comm.c:1.1.1.1.6.1.2.3
--- freeswan/pluto/kernel_comm.c:1.1.1.1.6.2	Fri Jul  5 00:16:22 2002
+++ freeswan/pluto/kernel_comm.c	Mon Jul  8 09:05:40 2002
@@ -47,7 +47,12 @@
 #include "adns.h"	/* needs <resolv.h> */
 #include "dnskey.h"	/* needs keys.h and adns.h */
 #include "server.h"
-
+#include "kernel_alg.h"
+#include "ike_alg.h"
+#ifndef NO_DB_OPS_STATS
+#define NO_DB_CONTEXT
+#include "db_ops.h"
+#endif
 /* helper variables and function to decode strings from whack message */
 
 static char *next_str
@@ -156,6 +161,8 @@
 	|| !unpack_str(&msg.right.cert)		/* string 6 */
 	|| !unpack_str(&msg.right.updown)	/* string 7 */
 	|| !unpack_str(&msg.keyid)		/* string 8 */
+	|| !unpack_str(&msg.ike)		/* string 9 */
+	|| !unpack_str(&msg.esp)		/* string 10 */
 	|| str_roof - next_str != (ptrdiff_t)msg.keyval.len)	/* check chunk */
 	{
 	    ugh = "message from whack contains bad string";
@@ -398,6 +405,18 @@
     {
 	show_ifaces_status();
 	whack_log(RC_COMMENT, BLANK_FORMAT);	/* spacer */
+#ifndef NO_KERNEL_ALG
+	kernel_alg_show_status();
+	whack_log(RC_COMMENT, BLANK_FORMAT);	/* spacer */
+#endif
+#ifndef NO_IKE_ALG
+	ike_alg_show_status();
+	whack_log(RC_COMMENT, BLANK_FORMAT);	/* spacer */
+#endif
+#ifndef NO_DB_OPS_STATS
+	db_ops_show_status();
+	whack_log(RC_COMMENT, BLANK_FORMAT);	/* spacer */
+#endif
 	show_connections_status();
 	whack_log(RC_COMMENT, BLANK_FORMAT);	/* spacer */
 	show_states_status();
Index: freeswan/pluto/spdb.c
diff -u freeswan/pluto/spdb.c:1.1.1.1.6.2 freeswan/pluto/spdb.c:1.1.1.1.6.1.2.4
--- freeswan/pluto/spdb.c:1.1.1.1.6.2	Fri Jul  5 00:16:22 2002
+++ freeswan/pluto/spdb.c	Fri Jul  5 00:35:30 2002
@@ -40,6 +40,10 @@
 #include "md5.h"
 #include "crypto.h" /* requires sha1.h and md5.h */
 
+#include "alg_info.h"
+#include "kernel_alg.h"
+#include "ike_alg.h"
+#include "db_ops.h"
 #define AD(x) x, elemsof(x)	/* Array Description */
 #define AD_NULL NULL, 0
 
@@ -370,7 +374,7 @@
 		, val, enum_show(d, val)));
     return TRUE;
 }
-
+#define return_on(var, val) do { var=val;goto return_out; } while(0);
 /* Output an SA, as described by a db_sa.
  * This has the side-effect of allocating SPIs for us.
  */
@@ -383,9 +387,13 @@
 {
     pb_stream sa_pbs;
     int pcn;
+    bool ret = FALSE;
     bool ah_spi_generated = FALSE
 	, esp_spi_generated = FALSE
 	, ipcomp_cpi_generated = FALSE;
+#if !defined NO_KERNEL_ALG || !defined NO_IKE_ALG
+    struct db_context *db_ctx = NULL;
+#endif
 
     /* SA header out */
     {
@@ -394,13 +402,13 @@
 	sa.isasa_np = np;
 	st->st_doi = sa.isasa_doi = ISAKMP_DOI_IPSEC;	/* all we know */
 	if (!out_struct(&sa, &isakmp_sa_desc, outs, &sa_pbs))
-	    return FALSE;
+	    return_on(ret, FALSE);
     }
 
     /* within SA: situation out */
     st->st_situation = SIT_IDENTITY_ONLY;
     if (!out_struct(&st->st_situation, &ipsec_sit_desc, &sa_pbs, NULL))
-	return FALSE;
+	return_on(ret, FALSE);
 
     /* within SA: Proposal Payloads
      *
@@ -435,9 +443,58 @@
 	    proposal.isap_spisize = oakley_mode ? 0
 		: p->protoid == PROTO_IPCOMP ? IPCOMP_CPI_SIZE
 		: IPSEC_DOI_SPI_SIZE;
+#ifndef NO_KERNEL_ALG
+	    /*	
+	     *	In quick mode ONLY, create proposal for
+	     *	runtime kernel algos
+	     *
+	     *  replace ESP proposals
+	     *  with runtime created one
+	     */
+	    if (!oakley_mode && p->protoid==PROTO_IPSEC_ESP) {
+		    DBG(DBG_CONTROL | DBG_CRYPT, 
+			if (st->st_connection->alg_info_esp) {
+			    static char buf[256]="";
+			    alg_info_snprint(buf, sizeof (buf), 
+				    (struct alg_info *)st->st_connection->alg_info_esp);
+			    DBG_log(buf);
+			 }
+		    );
+		    db_ctx=kernel_alg_db_new(st->st_connection->alg_info_esp, st->st_policy);
+		    p = db_prop_get(db_ctx);
+
+		    if (!p || p->trans_cnt==0) {
+			loglog(RC_LOG_SERIOUS, 
+				"empty IPSEC SA proposal to send "
+				"(no kernel algorithms for esp selection)");
+			return_on(ret, FALSE);
+		    }
+	    }
+#endif
+#ifndef NO_IKE_ALG
+	    if (oakley_mode && p->protoid==PROTO_ISAKMP) {
+		    DBG(DBG_CONTROL | DBG_CRYPT, 
+			if (st->st_connection->alg_info_ike) {
+			    static char buf[256]="";
+			    alg_info_snprint(buf, sizeof (buf), 
+				    (struct alg_info *)st->st_connection->alg_info_ike);
+			    DBG_log(buf);
+			 }
+		    );
+		    db_ctx=ike_alg_db_new(st->st_connection->alg_info_ike,
+				st->st_policy);
+		    p = db_prop_get(db_ctx);
+		    if (!p || p->trans_cnt==0) {
+			loglog(RC_LOG_SERIOUS, 
+					"empty ISAKMP SA proposal to send "
+					"(no algorithms for ike selection?)");
+			return_on(ret, FALSE);
+		    }
+	    }
+#endif
 	    proposal.isap_notrans = p->trans_cnt;
 	    if (!out_struct(&proposal, &isakmp_proposal_desc, &sa_pbs, &proposal_pbs))
-		return FALSE;
+		return_on(ret, FALSE);
 
 	    /* Per-protocols stuff:
 	     * Set trans_desc.
@@ -495,7 +552,7 @@
 		    {
 			st->st_ipcomp.our_spi = get_my_cpi();
 			if (st->st_ipcomp.our_spi == 0)
-			    return FALSE;	/* problem generating CPI */
+			    return_on(ret, FALSE);	/* problem generating CPI */
 
 			ipcomp_cpi_generated = TRUE;
 		    }
@@ -506,7 +563,7 @@
 		     + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE
 		    , IPCOMP_CPI_SIZE
 		    , &proposal_pbs, "CPI"))
-			return FALSE;
+			return_on(ret, FALSE);
 		    break;
 		default:
 		    impossible();
@@ -520,7 +577,7 @@
 		    }
 		    if (!out_raw((u_char *)spi_ptr, IPSEC_DOI_SPI_SIZE
 		    , &proposal_pbs, "SPI"))
-			return FALSE;
+			return_on(ret, FALSE);
 		}
 	    }
 
@@ -537,7 +594,7 @@
 		trans.isat_transnum = tn;
 		trans.isat_transid = t->transid;
 		if (!out_struct(&trans, trans_desc, &proposal_pbs, &trans_pbs))
-		    return FALSE;
+		    return_on(ret, FALSE);
 
 		/* Within tranform: Attributes. */
 
@@ -613,7 +670,15 @@
 	/* end of a conjunction of proposals */
     }
     close_output_pbs(&sa_pbs);
-    return TRUE;
+    ret = TRUE;
+
+return_out:
+
+#if !defined NO_KERNEL_ALG || !defined NO_IKE_ALG
+    if (db_ctx)
+	    db_destroy(db_ctx);
+#endif
+    return ret;
 }
 
 /* Handle long form of duration attribute.
@@ -670,6 +735,9 @@
     bool selection,	/* if this SA is a selection, only one tranform can appear */
     struct state *st)	/* current state object */
 {
+#ifndef NO_IKE_ALG
+    struct connection *c = st->st_connection;
+#endif
     u_int32_t ipsecdoisit;
     pb_stream proposal_pbs;
     struct isakmp_proposal proposal;
@@ -856,6 +924,14 @@
 	    switch (a.isaat_af_type)
 	    {
 		case OAKLEY_ENCRYPTION_ALGORITHM | ISAKMP_ATTR_AF_TV:
+#ifndef NO_IKE_ALG
+		    if (ike_alg_enc_ok(val, 0, c->alg_info_ike, &ugh)) {
+		    /* if (ike_alg_enc_present(val)) { */
+			ta.encrypt = val;
+			ta.encrypter = crypto_get_encrypter(val);
+			ta.enckeylen = ta.encrypter->keydeflen;
+		    } else 
+#endif
 		    switch (val)
 		    {
 #if 0	/* we don't feel DES is safe */
@@ -863,7 +939,7 @@
 #endif
 		    case OAKLEY_3DES_CBC:
 			ta.encrypt = val;
-			ta.encrypter = &oakley_encrypter[val];
+			ta.encrypter = crypto_get_encrypter(val);
 			break;
 		    default:
 			ugh = builddiag("%s is not supported"
@@ -872,17 +948,25 @@
 		    break;
 
 		case OAKLEY_HASH_ALGORITHM | ISAKMP_ATTR_AF_TV:
+#ifndef NO_IKE_ALG
+		    if (ike_alg_hash_present(val)) {
+			ta.hash = val;
+			ta.hasher = crypto_get_hasher(val);
+		    } else 
+#endif
+/* #else */
 		    switch (val)
 		    {
 		    case OAKLEY_MD5:
 		    case OAKLEY_SHA:
 			ta.hash = val;
-			ta.hasher = &oakley_hasher[val];
+			ta.hasher = crypto_get_hasher(val);
 			break;
 		    default:
 			ugh = builddiag("%s is not supported"
 			    , enum_show(&oakley_hash_names, val));
 		    }
+/* #endif */
 		    break;
 
 		case OAKLEY_AUTHENTICATION_METHOD | ISAKMP_ATTR_AF_TV:
@@ -1006,10 +1090,33 @@
 		    }
 		    break;
 
+#ifndef NO_IKE_ALG
+		case OAKLEY_KEY_LENGTH | ISAKMP_ATTR_AF_TV:
+		    if ((seen_attrs & LELEM(OAKLEY_ENCRYPTION_ALGORITHM)) == 0)
+		    {
+			ugh = "OAKLEY_KEY_LENGTH attribute not preceded by OAKLEY_ENCRYPTION_ALGORITHM attribute";
+			break;
+		    }
+		    if (ta.encrypter == NULL)
+		    {
+			ugh = "NULL encrypter with seen OAKLEY_ENCRYPTION_ALGORITHM";
+		        break;
+		    }
+		    /*
+		     * check if this keylen is compatible with 
+		     * specified alg_info_ike
+		     */
+		    if (!ike_alg_enc_ok(ta.encrypt, val, c->alg_info_ike, &ugh)) {
+			ugh = "peer proposed key_len not valid for encrypt algo setup specified";
+		    }
+		    ta.enckeylen=val;
+		    break;
+#else
+		case OAKLEY_KEY_LENGTH | ISAKMP_ATTR_AF_TV:
+#endif
 #if 0 /* not yet supported */
 		case OAKLEY_GROUP_TYPE | ISAKMP_ATTR_AF_TV:
 		case OAKLEY_PRF | ISAKMP_ATTR_AF_TV:
-		case OAKLEY_KEY_LENGTH | ISAKMP_ATTR_AF_TV:
 		case OAKLEY_FIELD_SIZE | ISAKMP_ATTR_AF_TV:
 
 		case OAKLEY_GROUP_PRIME | ISAKMP_ATTR_AF_TV:
@@ -1804,13 +1911,19 @@
 
 		previous_transnum = esp_trans.isat_transnum;
 
+#ifndef NO_KERNEL_ALG
+		if (!kernel_alg_esp_enc_ok(esp_attrs.transid, esp_attrs.key_len,
+			c->alg_info_esp))
+#endif
 		switch (esp_attrs.transid)
 		{
 #if 0	/* we don't feel single DES is safe */
 		    case ESP_DES:
 #endif
+#ifdef NO_KERNEL_ALG	/* strictly use runtime information */
 		    case ESP_3DES:
 			break;
+#endif
 
 #ifdef SUPPORT_ESP_NULL	/* should be about as secure as AH-only */
 		    case ESP_NULL:
@@ -1837,7 +1950,9 @@
 				, ip_str(&c->that.host_addr)));
 			continue;   /* try another */
 		}
-
+#ifndef NO_KERNEL_ALG
+		if (!kernel_alg_esp_auth_ok(esp_attrs.auth, c->alg_info_esp))
+#endif
 		switch (esp_attrs.auth)
 		{
 		    case AUTH_ALGORITHM_NONE:
@@ -1849,9 +1964,11 @@
 			    continue;   /* try another */
 			}
 			break;
+#ifdef NO_KERNEL_ALG	/* strictly use runtime information */
 		    case AUTH_ALGORITHM_HMAC_MD5:
 		    case AUTH_ALGORITHM_HMAC_SHA1:
 			break;
+#endif
 		    default:
 			DBG(DBG_CONTROL | DBG_CRYPT
 			    , DBG_log("unsupported ESP auth alg %s from %s"
Index: freeswan/pluto/whack.c
diff -u freeswan/pluto/whack.c:1.1.1.1.6.3 freeswan/pluto/whack.c:1.1.1.1.6.1.2.5
--- freeswan/pluto/whack.c:1.1.1.1.6.3	Fri Jul  5 00:16:22 2002
+++ freeswan/pluto/whack.c	Fri Jul  5 00:35:30 2002
@@ -67,7 +67,6 @@
 	    " \\\n   "
 	    "   "
 	    " [--updown <updown>]"
-	    " \\\n   "
 	    " --to"
 	    " (--host <ip-address> | --id <identity> | --cert <path>)"
 	    " [--ikeport <port-number>]"
@@ -80,7 +79,6 @@
 	    " \\\n   "
 	    "   "
 	    " [--updown <updown>]"
-	    " \\\n   "
 	    " [--psk]"
 	    " [--rsasig]"
 	    " \\\n   "
@@ -97,6 +95,9 @@
 	    " [--reykeyfuzz <percentage>]"
 	    " \\\n   "
 	    " [--keyingtries <count>]"
+	    " \\\n   "
+	    " [--esp <esp-algos>]"
+	    " \\\n   "
 	    " [--dontrekey]"
 	    "\n\n"
 	"routing: whack"
@@ -300,8 +301,11 @@
     CD_IPSECLIFETIME,
     CD_RKMARGIN,
     CD_RKFUZZ,
-    CD_KTRIES
-#   define CD_LAST CD_KTRIES	/* last connection description */
+    CD_KTRIES,
+    CD_IKE,
+    CD_PFSGROUP,
+    CD_ESP	
+#   define CD_LAST CD_ESP	/* last connection description */
 
 #ifdef DEBUG	/* must be last so others are less than 32 to fit in lset_t */
 #   define DBGOPT_FIRST DBGOPT_NONE
@@ -409,6 +413,9 @@
     { "rekeywindow", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG },	/* OBSOLETE */
     { "rekeyfuzz", required_argument, NULL, CD_RKFUZZ + OO + NUMERIC_ARG },
     { "keyingtries", required_argument, NULL, CD_KTRIES + OO + NUMERIC_ARG },
+    { "ike", required_argument, NULL, CD_IKE + OO },
+    { "pfsgroup", required_argument, NULL, CD_PFSGROUP + OO },
+    { "esp", required_argument, NULL, CD_ESP + OO },
 
 #ifdef DEBUG
     { "debug-none", no_argument, NULL, DBGOPT_NONE + OO },
@@ -554,6 +561,7 @@
 main(int argc, char **argv)
 {
     struct whack_message msg;
+    char esp_buf[256];	/* uses snprintf */
     lset_t
 	opts_seen = LEMPTY,
 	cd_seen = LEMPTY,
@@ -570,6 +578,9 @@
     msg.name = NULL;
     msg.keyid = NULL;
     msg.keyval.ptr = NULL;
+    msg.esp = NULL;
+    msg.pfsgroup = NULL;
+    msg.ike = NULL;
 
     msg.sa_ike_life_seconds = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT;
     msg.sa_ipsec_life_seconds = PLUTO_SA_LIFE_DURATION_DEFAULT;
@@ -894,7 +905,6 @@
 	    msg.right.updown = optarg;
 	    continue;
 
-
 	case CD_TO:		/* --to */
 	    /* process right end, move it to left, reset it */
 	    if ((cd_seen & LELEM(CD_HOST-CD_FIRST)) == 0)
@@ -939,6 +949,18 @@
 	    msg.sa_keying_tries = opt_whole;
 	    continue;
 
+	case CD_IKE:	/* --ike <ike_alg1,ike_alg2,...> */
+	    msg.ike = optarg;
+	    continue;
+	    
+	case CD_PFSGROUP:	/* --pfsgroup modpXXXX */
+	    msg.pfsgroup = optarg;
+	    continue;
+
+	case CD_ESP:	/* --esp <esp_alg1,esp_alg2,...> */
+	    msg.esp = optarg;
+	    continue;
+
 	case CD_CONNIPV4:
 	    if (cd_seen & LELEM(CD_CONNIPV6 - CD_FIRST))
 		diag("--ipv4 conflicts with --ipv6");
@@ -1118,6 +1140,13 @@
     check_life_time(msg.sa_ipsec_life_seconds, SA_LIFE_DURATION_MAXIMUM
 	, "ipseclifetime", &msg);
 
+    /* build esp message as esp="<esp>;<pfsgroup>" */
+    if (msg.pfsgroup) {
+	    snprintf(esp_buf, sizeof (esp_buf), "%s;%s", 
+		    msg.esp ? msg.esp : "",
+		    msg.pfsgroup ? msg.pfsgroup : "");
+	    msg.esp=esp_buf;
+    }
     /* pack strings for inclusion in message */
     next_str = msg.string;
     str_roof = &msg.string[sizeof(msg.string)];
@@ -1130,6 +1159,8 @@
     || !pack_str(&msg.right.cert)	/* string 6 */
     || !pack_str(&msg.right.updown)	/* string 7 */
     || !pack_str(&msg.keyid)		/* string 8 */
+    || !pack_str(&msg.ike)		/* string 9 */
+    || !pack_str(&msg.esp)		/* string 10 */
     || str_roof - next_str < (ptrdiff_t)msg.keyval.len)    /* chunk (sort of string 5) */
 	diag("too many bytes of strings to fit in message to pluto");
 
Index: freeswan/pluto/whack.h
diff -u freeswan/pluto/whack.h:1.1.1.1.6.3 freeswan/pluto/whack.h:1.1.1.1.6.1.2.5
--- freeswan/pluto/whack.h:1.1.1.1.6.3	Fri Jul  5 00:16:22 2002
+++ freeswan/pluto/whack.h	Fri Jul  5 00:35:30 2002
@@ -84,6 +84,10 @@
     sa_family_t addr_family;	/* between gateways */
     sa_family_t tunnel_addr_family;	/* between clients */
 
+    char *ike;		/* ike algo string (separated by commas) */
+    char *pfsgroup;    /* pfsgroup will be "encapsulated" in esp string for pluto */
+    char *esp;		/* esp algo string (separated by commas) */
+
     /* for WHACK_KEY: */
     bool whack_key;
     bool whack_addkey;
Index: freeswan/pluto/demux.c
diff -u freeswan/pluto/demux.c:1.1.1.1.6.1 freeswan/pluto/demux.c:1.1.1.1.6.1.2.1
--- freeswan/pluto/demux.c:1.1.1.1.6.1	Fri May 24 19:17:53 2002
+++ freeswan/pluto/demux.c	Mon May 27 12:46:37 2002
@@ -135,6 +135,7 @@
 #include "md5.h"
 #include "sha1.h"
 #include "crypto.h" /* requires sha1.h and md5.h */
+#include "ike_alg.h"
 #include "log.h"
 #include "demux.h"	/* needs packet.h */
 #include "ipsec_doi.h"	/* needs demux.h and state.h */
@@ -1396,7 +1397,7 @@
 	{
 	    const struct encrypt_desc *e = st->st_oakley.encrypter;
 
-	    if (pbs_left(&md->message_pbs) % e->blocksize != 0)
+	    if (pbs_left(&md->message_pbs) % e->enc_blocksize != 0)
 	    {
 		loglog(RC_LOG_SERIOUS, "malformed message: not a multiple of encryption blocksize");
 		/* XXX Could send notification back */
@@ -1417,8 +1418,8 @@
 		st->st_new_iv_len = st->st_iv_len;
 		memcpy(st->st_new_iv, st->st_iv, st->st_new_iv_len);
 	    }
-	    e->crypt(FALSE, md->message_pbs.cur, pbs_left(&md->message_pbs)
-		, st);
+	    crypto_cbc_encrypt(e, FALSE, md->message_pbs.cur, 
+			    pbs_left(&md->message_pbs) , st);
 	}
 
 	DBG_cond_dump(DBG_CRYPT, "decrypted:\n", md->message_pbs.cur,
Index: freeswan/pluto/state.h
diff -u freeswan/pluto/state.h:1.1.1.1.4.1 freeswan/pluto/state.h:1.1.1.1.6.2
--- freeswan/pluto/state.h:1.1.1.1.4.1	Fri Jul  5 00:16:22 2002
+++ freeswan/pluto/state.h	Fri Jul  5 00:35:30 2002
@@ -52,6 +52,7 @@
  */
 struct oakley_trans_attrs {
     u_int16_t encrypt;		/* Encryption algorithm */
+    u_int16_t enckeylen;	/* encryption key len (bits) */
     const struct encrypt_desc *encrypter;	/* package of encryption routines */
     u_int16_t hash;		/* Hash algorithm */
     const struct hash_desc *hasher;	/* package of hashing routines */
Index: freeswan/pluto/alg/Makefile
diff -u /dev/null freeswan/pluto/alg/Makefile:1.1.4.1
--- /dev/null	Fri Jul 12 16:03:47 2002
+++ freeswan/pluto/alg/Makefile	Mon May 27 12:46:37 2002
@@ -0,0 +1,98 @@
+# pluto/alg Makefile
+# Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
+#
+# 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.
+#
+# $Id: Makefile,v 1.1.4.1 2002/05/27 15:46:37 jjo Exp $
+
+Make.common: ../Makefile
+	make -s -C .. showdefs > $@
+
+-include Make.common
+
+LIBCRYPTO:=../../libcrypto
+ALLFLAGS=$(CPPFLAGS) $(CFLAGS) -I .. -I-  -I ../../lib -I ../../libcrypto
+LIBALG := libalg.o
+
+all : $(LIBALG)
+
+include $(wildcard Makefile.ike_alg_*)
+#include $(wildcard Makefile.ike_alg_[ab]*)
+
+$(LIBALG): ike_alginit.o $(ALG_OBJS) $(ALG_LIBS)
+	$(LD) -r -o $@ $^
+
+# Search for IKE_ALG_INIT_NAME: in ike_alg_*.c to
+# build ike_alginit.c:ike_alginit()
+
+ike_alginit.c: $(ALG_SRCS) Makefile
+	@awk '	\
+		BEGIN { print "extern int ike_alg_init(void); \
+			int ike_alg_init(void) {" } \
+		/IKE_ALG_INIT_NAME:/ \
+			{ print "{ extern int " $$2" (void); " $$2 "();}" } \
+		END   { print "return 0;}" } \
+		' $(ALG_SRCS) /dev/null > $@ 
+
+clean :
+	@for i in $(ALG_DIRS);do make -C $$i clean;done
+	rm -f *.[oa] ike_alginit.c Make.common
+
+gatherdeps:
+	@ls $(ALG_SRCS) | grep '\.c' | sed -e 's/\(.*\)\.c$$/\1.o: \1.c/'
+	@echo
+	@ls $(ALG_SRCS) | grep '\.c' | xargs grep '^#[ 	]*include[ 	]*"' | \
+		sed -n -e '/#include.*"lib/d' \
+		-e 's/\.c:#[ 	]*include[ 	]*"/.o: ..\//' -e 's/".*//p'
+
+# Dependencies generated by "make gatherdeps":
+
+ike_alg_aes.o: ike_alg_aes.c
+ike_alg_blowfish.o: ike_alg_blowfish.c
+ike_alg_cast.o: ike_alg_cast.c
+ike_alg_sha2.o: ike_alg_sha2.c
+
+ike_alg_aes.o: ../md5.h
+ike_alg_aes.o: ../sha1.h
+ike_alg_aes.o: ../constants.h
+ike_alg_aes.o: ../defs.h
+ike_alg_aes.o: ../state.h
+ike_alg_aes.o: ../log.h
+ike_alg_aes.o: ../crypto.h
+ike_alg_aes.o: ../alg_info.h
+ike_alg_aes.o: ../ike_alg.h
+ike_alg_blowfish.o: ../md5.h
+ike_alg_blowfish.o: ../sha1.h
+ike_alg_blowfish.o: ../constants.h
+ike_alg_blowfish.o: ../defs.h
+ike_alg_blowfish.o: ../state.h
+ike_alg_blowfish.o: ../log.h
+ike_alg_blowfish.o: ../crypto.h
+ike_alg_blowfish.o: ../alg_info.h
+ike_alg_blowfish.o: ../ike_alg.h
+ike_alg_cast.o: ../md5.h
+ike_alg_cast.o: ../sha1.h
+ike_alg_cast.o: ../constants.h
+ike_alg_cast.o: ../defs.h
+ike_alg_cast.o: ../state.h
+ike_alg_cast.o: ../log.h
+ike_alg_cast.o: ../crypto.h
+ike_alg_cast.o: ../alg_info.h
+ike_alg_cast.o: ../ike_alg.h
+ike_alg_sha2.o: ../md5.h
+ike_alg_sha2.o: ../sha1.h
+ike_alg_sha2.o: ../constants.h
+ike_alg_sha2.o: ../defs.h
+ike_alg_sha2.o: ../state.h
+ike_alg_sha2.o: ../log.h
+ike_alg_sha2.o: ../crypto.h
+ike_alg_sha2.o: ../alg_info.h
+ike_alg_sha2.o: ../ike_alg.h
Index: freeswan/utils/_confread
diff -u freeswan/utils/_confread:1.1.1.1.6.3 freeswan/utils/_confread:1.1.1.1.6.1.2.4
--- freeswan/utils/_confread:1.1.1.1.6.3	Fri Jul  5 00:16:22 2002
+++ freeswan/utils/_confread	Fri Jul  5 00:35:30 2002
@@ -124,10 +124,10 @@
 
 	good = "also type auto authby _plutodevel"
 	left = " left leftsubnet leftnexthop leftfirewall leftupdown"
-	akey = " keyexchange auth pfs keylife rekey rekeymargin rekeyfuzz"
+	akey = " keyexchange auth pfs pfsgroup keylife rekey rekeymargin rekeyfuzz"
 	akey = akey " compress"
 	obs = " lifetime rekeystart rekeytries"
-	akey = akey " keyingtries ikelifetime disablearrivalcheck" obs
+	akey = akey " keyingtries ikelifetime disablearrivalcheck ike" obs
 	mkey = " spibase spi esp espenckey espauthkey espreplay_window"
 	left = left " leftespenckey leftespauthkey leftahkey"
 	left = left " leftespspi leftahspi leftid leftrsasigkey leftrsasigkey2"
Index: freeswan/utils/auto
diff -u freeswan/utils/auto:1.1.1.1.6.3 freeswan/utils/auto:1.1.1.1.6.1.2.4
--- freeswan/utils/auto:1.1.1.1.6.3	Fri Jul  5 00:16:22 2002
+++ freeswan/utils/auto	Fri Jul  5 00:35:30 2002
@@ -401,12 +401,21 @@
 			fail("unknown authby value " v(s["authby"]))
 
 		settings = "--encrypt"
+		default("ike", "3des")
+		if (s["ike"] != "")
+			settings = settings " --ike " qs("ike")
+		default("esp", "3des")
+		if (s["esp"] != "")
+			settings = settings " --esp " qs("esp")
 		if (s["type"] != "transport")
 			settings = settings " --tunnel"
 		if (s["auth"] == "ah")
 			settings = settings " --authenticate"
-		if (s["pfs"] == "yes")
+		if (s["pfs"] == "yes") {
 			settings = settings " --pfs"
+			if (s["pfsgroup"] != "")
+				settings = settings " --pfsgroup " qs("pfsgroup")
+		}
 		if (s["compress"] == "yes")
 			settings = settings " --compress"
 		if (op == "--replace")

