Blob Blame History Raw
diff -Naur libreswan-3.12-orig/programs/pluto/cavp.c libreswan-3.12/programs/pluto/cavp.c
--- libreswan-3.12-orig/programs/pluto/cavp.c	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/cavp.c	2015-05-06 11:45:32.912301324 -0400
@@ -0,0 +1,305 @@
+/*
+ * Parse CAVP test vectors, for libreswan
+ *
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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 <stdbool.h> */
+#include <string.h>
+#include <stdlib.h>
+
+#include "constants.h"
+#include "lswalloc.h"
+#include "ike_alg.h"
+#include "crypto.h"
+#include "crypt_symkey.h"
+#include "test_buffer.h"
+
+#include "cavp.h"
+#include "cavp_print.h"
+#include "cavp_ikev1.h"
+#include "cavp_ikev2.h"
+
+struct cavp *cavps[] = {
+	&cavp_ikev1_sig,
+	&cavp_ikev1_psk,
+	&cavp_ikev2,
+	NULL
+};
+
+#define BUF_SIZE 4096
+
+static struct cavp_entry *lookup_entry(struct cavp_entry *entries, const char *key)
+{
+	struct cavp_entry *entry;
+	for (entry = entries; entry->op != NULL; entry++) {
+		if (strcmp(entry->key, key) == 0) {
+			return entry;
+		}
+	}
+	return NULL;
+}
+
+enum what { INITIAL, BLANK, CONFIG, DATA, RUN, FINAL } state = INITIAL;
+
+static void error_state(enum what state, enum what what)
+{
+	fprintf(stderr, "bad state %d what %d\n", state, what);
+	exit(1);
+}
+
+static struct cavp *cavp;
+
+static void next_state(enum what what)
+{
+	switch (state) {
+	case INITIAL:
+		switch (what) {
+		case CONFIG:
+			state = CONFIG;
+			break;
+		case BLANK:
+			break;
+		default:
+			error_state(state, what);
+		}
+		break;
+	case CONFIG:
+		switch (what) {
+		case CONFIG:
+			break;
+		case BLANK:
+			cavp->print_config();
+			state = DATA;
+			break;
+		default:
+			error_state(state, what);
+		}
+		break;
+	case DATA:
+		switch (what) {
+		case DATA:
+			break;
+		case BLANK:
+			cavp->run();
+			state = RUN;
+			break;
+		default:
+			error_state(state, what);
+		}
+		break;
+	case RUN:
+		switch (what) {
+		case CONFIG:
+			state = CONFIG;
+			break;
+		case DATA:
+			state = DATA;
+			break;
+		case BLANK:
+			break;
+		default:
+			error_state(state, what);
+		}
+		break;
+	default:
+		error_state(state, what);
+		break;
+	}
+}
+
+struct hash_desc *hasher;
+char hasher_name[BUF_SIZE];
+
+void hash(struct cavp_entry *entry,
+	  const char *value UNUSED)
+{
+	strcpy(hasher_name, entry->key);
+	hasher = ike_alg_get_hasher(entry->value);
+	if (hasher == NULL) {
+		fprintf(stderr, "hasher %s not found\n", entry->key);
+	}
+}
+
+void chunk(struct cavp_entry *entry,
+	   const char *value)
+{
+	freeanychunk(*(entry->chunk));
+	*(entry->chunk) = decode_hex_to_chunk(entry->key, value);
+}
+
+void symkey(struct cavp_entry *entry,
+	    const char *value)
+{
+	free_any_symkey(__func__, entry->symkey);
+	chunk_t chunk = decode_hex_to_chunk(entry->key, value);
+	*(entry->symkey) = chunk_to_key(CKM_DH_PKCS_DERIVE, chunk);
+	freeanychunk(chunk);
+}
+
+void number(struct cavp_entry *entry,
+	    const char *value)
+{
+	*(entry->number) = atoi(value);
+}
+
+void ignore(struct cavp_entry *entry UNUSED,
+	    const char *value UNUSED)
+{
+}
+
+static void cavp_parser()
+{
+	char line[BUF_SIZE];
+	while (TRUE) {
+		if (fgets(line, sizeof(line), stdin) == NULL) {
+			int error = ferror(stdin);
+			if (error) {
+				fprintf(stderr, "Unexpected error: %s\n",
+					strerror(error));
+				exit(1);
+			}
+			break;
+		}
+		/* trim trailing cr/nl. */
+		int last = strlen(line) - 1;
+		while (last >= 0 && strchr("\r\n", line[last]) != NULL) {
+			last--;
+		}
+		line[last + 1] = '\0';
+		/* break the line up */
+		char *lparen = strchr(line, '[');
+		char *eq = strchr(line, '=');
+		char *rparen = strchr(line, ']');
+		if (line[0] == '\0') {
+			next_state(BLANK);
+			/* blank */
+			print_line(line);
+		} else if (line[0] == '#') {
+			/* # .... comment */
+			if (cavp == NULL) {
+				struct cavp **cavpp;
+				for (cavpp = cavps; *cavpp != NULL; cavpp++) {
+					if (strstr(line, (*cavpp)->description) != NULL) {
+						cavp = *cavpp;
+						fprintf(stderr, "\ntest: %s (guess)\n\n", cavp->description);
+						break;
+					}
+				}
+			}
+			print_line(line);
+		} else if (lparen != NULL && rparen != NULL) {
+			next_state(CONFIG);
+			/* "[" <key> [ " = " <value> ] "]" */
+			*rparen = '\0';
+			char *key = lparen + 1;
+			char *value;
+			if (eq == NULL) {
+				value = NULL;
+			} else {
+				value = eq + 2;
+				*(eq - 1) = '\0';
+			}
+			struct cavp_entry *entry = lookup_entry(cavp->config, key);
+			if (entry == NULL) {
+				fprintf(stderr, "unknown config entry: ['%s' = '%s']\n", key, value);
+				exit(1);
+			}
+			entry->op(entry, value);
+		} else if (eq != NULL) {
+			next_state(DATA);
+			*(eq - 1) = '\0';
+			char *key = line;
+			char *value = eq + 2;
+			struct cavp_entry *entry = lookup_entry(cavp->data, key);
+			if (entry == NULL) {
+				fprintf(stderr, "unknown data entry: '%s' = '%s'\n", key, value);
+				exit(1);
+			}
+			entry->op(entry, value);
+		} else {
+			fprintf(stderr, "bad line: '%s'\n", line);
+		}
+	}
+}
+
+static void usage()
+{
+	fprintf(stderr, "Usage: cavp [ -OPTION ] <test-vector>|-\n");
+	struct cavp **cavpp;
+	for (cavpp = cavps; *cavpp != NULL; cavpp++) {
+		fprintf(stderr, "\t-%s\t%s\n", (*cavpp)->alias, (*cavpp)->description);
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	if (argc <= 1) {
+		usage();
+		exit(1);
+	}
+	char **argp = argv + 1;
+
+	/* a -XXX option? */
+	if ((*argp)[0] == '-' && (*argp)[1] != '\0') {
+		struct cavp **cavpp;
+		for (cavpp = cavps; *cavpp != NULL; cavpp++) {
+			if (strcmp(argv[1]+1, (*cavpp)->alias) == 0) {
+				cavp = *cavpp;
+				fprintf(stderr, "test: %s\n", cavp->description);
+				break;
+			}
+		}
+		if (cavp == NULL) {
+			fprintf(stderr, "Unknown test %s\n", argv[1]);
+			usage();
+			exit(1);
+		}
+		argp++;
+	} else {
+		fprintf(stderr, "Guessing test type ...\n");
+	}
+
+	if (*argp == NULL) {
+		fprintf(stderr, "missing test file\n");
+		usage();
+		exit(1);
+	}
+	if (strcmp(*argp, "-") == 0) {
+		fprintf(stderr, "Reading from stdin\n");
+	} else {
+		fprintf(stderr, "reading from %s\n", *argp);
+		if (freopen(*argp, "r", stdin) == NULL) {
+			perror("freopen");
+			exit(1);
+		}
+	}
+	argp++;
+
+	if (*argp != NULL) {
+		fprintf(stderr, "unexpected %s", *argp);
+		usage();
+		exit(1);
+	}
+	
+	setbuf(stdout, NULL);
+
+	NSS_NoDB_Init(".");
+        init_crypto();
+
+	cavp_parser();
+
+	NSS_Shutdown();
+	return 0;
+}
diff -Naur libreswan-3.12-orig/programs/pluto/cavp.h libreswan-3.12/programs/pluto/cavp.h
--- libreswan-3.12-orig/programs/pluto/cavp.h	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/cavp.h	2015-05-06 11:45:32.912301324 -0400
@@ -0,0 +1,45 @@
+/*
+ * Parse CAVP test vectors, for libreswan
+ *
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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.
+ */
+
+struct hash_desc;
+
+struct cavp_entry {
+	const char *key;
+	void (*op)(struct cavp_entry *key, const char *value);
+	chunk_t *chunk;
+	PK11SymKey **symkey;
+	int *number;
+	struct hash_desc **hasher;
+	int value;
+};
+
+struct cavp {
+	const char *alias;
+	const char *description;
+	void (*print_config)(void);
+	void (*run)(void);
+	struct cavp_entry *config;
+	struct cavp_entry *data;
+};
+
+extern struct hash_desc *hasher;
+extern char hasher_name[];
+void hash(struct cavp_entry *entry, const char *value);
+
+void ignore(struct cavp_entry *entry, const char *value);
+void chunk(struct cavp_entry *entry, const char *value);
+void symkey(struct cavp_entry *entry, const char *value);
+void number(struct cavp_entry *entry, const char *value);
diff -Naur libreswan-3.12-orig/programs/pluto/cavp_ikev1.c libreswan-3.12/programs/pluto/cavp_ikev1.c
--- libreswan-3.12-orig/programs/pluto/cavp_ikev1.c	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/cavp_ikev1.c	2015-05-06 11:45:32.913301336 -0400
@@ -0,0 +1,174 @@
+/*
+ * Parse IKEv1 CAVP test functions, for libreswan
+ *
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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 <pk11pub.h>
+
+#include "lswalloc.h"
+#include "ike_alg.h"
+
+#include "ikev1_prf.h"
+#include "crypt_symkey.h"
+
+#include "cavp.h"
+#include "cavp_print.h"
+#include "cavp_ikev1.h"
+
+static int ni_length;
+static int nr_length;
+static int psk_length;
+static int g_xy_length;
+
+static struct cavp_entry config_entries[] = {
+	{ .key = "SHA-1", .op = hash, .value = OAKLEY_SHA1, },
+	{ .key = "SHA-224", .op = hash, .value = 0, },
+	{ .key = "SHA-256", .op = hash, .value = OAKLEY_SHA2_256, },
+	{ .key = "SHA-384", .op = hash, .value = OAKLEY_SHA2_384, },
+	{ .key = "SHA-512", .op = hash, .value = OAKLEY_SHA2_512, },
+	{ .key = "Ni length", .op = number, .number = &ni_length },
+	{ .key = "Nr length", .op = number, .number = &nr_length },
+	{ .key = "pre-shared-key length", .op = number, .number = &psk_length },
+	{ .key = "g^xy length", .op = number, .number = &g_xy_length },
+	{ .key = NULL }
+};
+
+static int count;
+static chunk_t psk;
+static chunk_t ni;
+static chunk_t nr;
+static chunk_t cky_i;
+static chunk_t cky_r;
+static PK11SymKey *g_xy;
+
+static struct cavp_entry data_entries[] = {
+	{ .key = "COUNT", .op = number, .number = &count },
+	{ .key = "g^xy", .op = symkey, .symkey = &g_xy },
+	{ .key = "Ni", .op = chunk, .chunk = &ni },
+	{ .key = "Nr", .op = chunk, .chunk = &nr },
+	{ .key = "CKY_I", .op = chunk, .chunk = &cky_i },
+	{ .key = "CKY_R", .op = chunk, .chunk = &cky_r },
+	{ .key = "pre-shared-key", .op = chunk, .chunk = &psk },
+	{ .key = "SKEYID", .op = ignore },
+	{ .key = "SKEYID_d", .op = ignore },
+	{ .key = "SKEYID_a", .op = ignore },
+	{ .key = "SKEYID_e", .op = ignore },
+	{ .key = "SKEYID_", .op = ignore },
+	{ .op = NULL }
+};
+
+static void ikev1_skeyid_alphabet(PK11SymKey *skeyid)
+{
+	PK11SymKey *skeyid_d =
+		ikev1_skeyid_d(hasher, skeyid,
+			       g_xy, cky_i, cky_r);
+	print_symkey("SKEYID_d", skeyid_d, 0);
+	
+	PK11SymKey *skeyid_a =
+		ikev1_skeyid_a(hasher, skeyid, skeyid_d,
+			       g_xy, cky_i, cky_r);
+	print_symkey("SKEYID_a", skeyid_a, 0);
+	
+	PK11SymKey *skeyid_e =
+		ikev1_skeyid_e(hasher, skeyid, skeyid_a,
+			       g_xy, cky_i, cky_r);
+	print_symkey("SKEYID_e", skeyid_e, 0);
+
+	free_any_symkey("skeyid_d", &skeyid_d);
+	free_any_symkey("skeyid_e", &skeyid_e);
+	free_any_symkey("skeyid_a", &skeyid_a);
+}
+
+static void print_sig_config()
+{
+	config_number("g^xy length", g_xy_length);
+	config_key(hasher_name);
+	config_number("Ni length", ni_length);
+	config_number("Nr length", nr_length);
+}
+
+static void run_sig(void)
+{
+	print_number("COUNT", count);
+	print_chunk("CKY_I", cky_i, 0);
+	print_chunk("CKY_R", cky_r, 0);
+	print_chunk("Ni", ni, 0);
+	print_chunk("Nr", nr, 0);
+	print_symkey("g^xy", g_xy, 0);
+
+	if (hasher == NULL) {
+		print_line(hasher_name);
+		return;
+	}
+
+	PK11SymKey *skeyid =
+		ikev1_signature_skeyid(hasher,
+				       ni, nr,
+				       g_xy);
+	print_symkey("SKEYID", skeyid, 0);
+	ikev1_skeyid_alphabet(skeyid);
+	free_any_symkey("skeyid", &skeyid);
+}
+
+struct cavp cavp_ikev1_sig = {
+	.alias = "v1sig",
+	.description = "IKE v1 Digital Signature Authentication",
+	.print_config = print_sig_config,
+	.run = run_sig,
+	.config = config_entries,
+	.data = data_entries,
+};
+
+static void print_psk_config(void)
+{
+	config_number("g^xy length", g_xy_length);
+	config_key(hasher_name);
+	config_number("Ni length", ni_length);
+	config_number("Nr length", nr_length);
+	config_number("pre-shared-key length", psk_length);
+}
+
+static void run_psk(void)
+{
+	print_number("COUNT", count);
+	print_chunk("CKY_I", cky_i, 0);
+	print_chunk("CKY_R", cky_r, 0);
+	print_chunk("Ni", ni, 0);
+	print_chunk("Nr", nr, 0);
+	print_symkey("g^xy", g_xy, 0);
+	print_chunk("pre-shared-key", psk, 0);
+
+	if (hasher == NULL) {
+		print_line(hasher_name);
+		return;
+	}
+
+	PK11SymKey *skeyid =
+		ikev1_pre_shared_key_skeyid(hasher,
+					    psk,
+					    ni, nr,
+					    g_xy);
+	print_symkey("SKEYID", skeyid, 0);
+	ikev1_skeyid_alphabet(skeyid);
+	free_any_symkey("skeyid", &skeyid);
+}
+
+struct cavp cavp_ikev1_psk = {
+	.alias = "v1psk",
+	.description = "IKE v1 Pre-shared Key Authentication",
+	.print_config = print_psk_config,
+	.run = run_psk,
+	.config = config_entries,
+	.data = data_entries,
+};
diff -Naur libreswan-3.12-orig/programs/pluto/cavp_ikev1.h libreswan-3.12/programs/pluto/cavp_ikev1.h
--- libreswan-3.12-orig/programs/pluto/cavp_ikev1.h	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/cavp_ikev1.h	2015-05-06 11:45:32.913301336 -0400
@@ -0,0 +1,18 @@
+/*
+ * Parse IKEv1 CAVP test functions, for libreswan
+ *
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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.
+ */
+
+struct cavp cavp_ikev1_sig;
+struct cavp cavp_ikev1_psk;
diff -Naur libreswan-3.12-orig/programs/pluto/cavp_ikev2.c libreswan-3.12/programs/pluto/cavp_ikev2.c
--- libreswan-3.12-orig/programs/pluto/cavp_ikev2.c	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/cavp_ikev2.c	2015-05-06 11:45:32.913301336 -0400
@@ -0,0 +1,141 @@
+/*
+ * Parse IKEv1 CAVP test functions, for libreswan
+ *
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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 <pk11pub.h>
+
+#include "lswalloc.h"
+#include "ike_alg.h"
+
+#include "crypt_symkey.h"
+#include "ikev2_prf.h"
+
+#include "cavp.h"
+#include "cavp_print.h"
+#include "cavp_ikev2.h"
+
+static int g_ir_length;
+static int ni_length;
+static int nr_length;
+static int dkm_length;
+static int child_sa_dkm_length;
+
+static struct cavp_entry config_entries[] = {
+	{ .key = "g^ir length", .op = number, .number = &g_ir_length },
+	{ .key = "SHA-1", .op = hash, .value = OAKLEY_SHA1, },
+	{ .key = "SHA-224", .op = hash, .value = 0, },
+	{ .key = "SHA-256", .op = hash, .value = OAKLEY_SHA2_256, },
+	{ .key = "SHA-384", .op = hash, .value = OAKLEY_SHA2_384, },
+	{ .key = "SHA-512", .op = hash, .value = OAKLEY_SHA2_512, },
+	{ .key = "Ni length", .op = number, .number = &ni_length },
+	{ .key = "Nr length", .op = number, .number = &nr_length },
+	{ .key = "DKM length", .op = number, .number = &dkm_length },
+	{ .key = "Child SA DKM length", .op = number, .number = &child_sa_dkm_length },
+	{ .key = NULL }
+};
+
+static void ikev2_config()
+{
+	config_number("g^ir length", g_ir_length);
+	config_key(hasher_name);
+	config_number("Ni length",ni_length);
+	config_number("Nr length",nr_length);
+	config_number("DKM length",dkm_length);
+	config_number("Child SA DKM length",child_sa_dkm_length);
+}
+
+static int count;
+static chunk_t ni;
+static chunk_t nr;
+static PK11SymKey *g_ir;
+static PK11SymKey *g_ir_new;
+static chunk_t spi_i;
+static chunk_t spi_r;
+
+static struct cavp_entry data_entries[] = {
+	{ .key = "COUNT", .op = number, .number = &count },
+	{ .key = "g^ir", .op = symkey, .symkey = &g_ir },
+	{ .key = "g^ir (new)", .op = symkey, .symkey = &g_ir_new },
+	{ .key = "Ni", .op = chunk, .chunk = &ni },
+	{ .key = "Nr", .op = chunk, .chunk = &nr },
+	{ .key = "SPIi", .op = chunk, .chunk = &spi_i },
+	{ .key = "SPIr", .op = chunk, .chunk = &spi_r },
+	{ .key = "SKEYSEED", .op = ignore },
+	{ .key = "DKM", .op = ignore },
+	{ .key = "DKM(Child SA)", .op = ignore },
+	{ .key = "DKM(Child SA D-H)", .op = ignore },
+	{ .key = "SKEYSEED(Rekey)", .op = ignore },
+	{ .op = NULL }
+};
+
+static void run_ikev2(void)
+{
+	print_number("COUNT", count);
+	print_chunk("Ni", ni, 0);
+	print_chunk("Nr", nr, 0);
+	print_symkey("g^ir", g_ir, 0);
+	print_symkey("g^ir (new)", g_ir_new, 0);
+	print_chunk("SPIi", spi_i, 0);
+	print_chunk("SPIr", spi_r, 0);
+	
+	if (hasher == NULL) {
+		print_line(hasher_name);
+		return;
+	}
+
+        /* SKEYSEED = prf(Ni | Nr, g^ir) */
+        PK11SymKey *skeyseed =
+                ikev2_ike_sa_skeyseed(hasher, ni, nr, g_ir);
+        print_symkey("SKEYSEED", skeyseed, 0);
+
+        /* prf+(SKEYSEED, Ni | Nr | SPIi | SPIr) */
+        PK11SymKey *dkm =
+                ikev2_ike_sa_keymat(hasher, skeyseed,
+                                    ni, nr, spi_i, spi_r, dkm_length / 8);
+        print_symkey("DKM", dkm, dkm_length / 8);
+
+        /* prf+(SK_d, Ni | Nr) */
+        PK11SymKey *SK_d = key_from_symkey_bytes(dkm, 0, hasher->hash_digest_len);
+        PK11SymKey *child_sa_dkm =
+                ikev2_child_sa_keymat(hasher, SK_d, NULL, ni, nr, child_sa_dkm_length / 8);
+        print_symkey("DKM(Child SA)", child_sa_dkm, child_sa_dkm_length / 8);
+
+        /* prf+(SK_d, g^ir (new) | Ni | Nr) */
+        PK11SymKey *child_sa_dkm_dh =
+                ikev2_child_sa_keymat(hasher, SK_d, g_ir_new, ni, nr,
+				      child_sa_dkm_length / 8);
+        print_symkey("DKM(Child SA D-H)", child_sa_dkm_dh, child_sa_dkm_length / 8);
+
+        /* prf(SK_d (old), g^ir (new) | Ni | Nr) */
+        PK11SymKey *skeyseed_rekey =
+                ikev2_ike_sa_rekey_skeyseed(hasher, SK_d, g_ir_new, ni, nr);
+        print_symkey("SKEYSEED(Rekey)", skeyseed_rekey, 0);
+
+	free_any_symkey("skeyseed", &skeyseed);
+	free_any_symkey("dkm", &dkm);
+	free_any_symkey("SK_d", &SK_d);
+	free_any_symkey("child_sa_dkm", &child_sa_dkm);
+	free_any_symkey("child_sa_dkm_dh", &child_sa_dkm_dh);
+	free_any_symkey("skeyseed_rekey", &skeyseed_rekey);
+}
+
+struct cavp cavp_ikev2 = {
+	.alias = "v2",
+	.description = "IKE v2",
+	.print_config = ikev2_config,
+	.run = run_ikev2,
+	.config = config_entries,
+	.data = data_entries,
+};
diff -Naur libreswan-3.12-orig/programs/pluto/cavp_ikev2.h libreswan-3.12/programs/pluto/cavp_ikev2.h
--- libreswan-3.12-orig/programs/pluto/cavp_ikev2.h	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/cavp_ikev2.h	2015-05-06 11:45:32.914301347 -0400
@@ -0,0 +1,17 @@
+/*
+ * Parse IKEv1 CAVP test functions, for libreswan
+ *
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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.
+ */
+
+struct cavp cavp_ikev2;
diff -Naur libreswan-3.12-orig/programs/pluto/cavp_print.c libreswan-3.12/programs/pluto/cavp_print.c
--- libreswan-3.12-orig/programs/pluto/cavp_print.c	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/cavp_print.c	2015-05-06 11:45:32.914301347 -0400
@@ -0,0 +1,73 @@
+/*
+ * Parse CAVP test vectors, for libreswan
+ *
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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 <stdlib.h>
+
+#include "constants.h"
+#include "lswalloc.h"
+#include "crypt_symkey.h"
+#include "cavp_print.h"
+
+/*
+ * The test vectors are CR-LF terminated, mimic this.
+ */
+static const char crlf[] = "\r\n";
+
+void config_key(const char *key)
+{
+	fputs("[", stdout);
+	fputs(key, stdout);
+	fputs("]", stdout);
+	fputs(crlf, stdout);
+}
+
+void config_number(const char *key, int number)
+{
+	printf("[%s = %d]%s", key, number, crlf);
+}
+
+void print_chunk(const char *prefix, chunk_t chunk, size_t binlen)
+{
+	printf("%s = ", prefix);
+        size_t len = binlen == 0 ? chunk.len
+                : binlen < chunk.len ? binlen
+                : chunk.len;
+        
+        size_t i = 0;
+        for (i = 0; i < len; i++) {
+                printf("%02x", chunk.ptr[i]);
+        }
+        printf("%s", crlf);
+}
+
+void print_symkey(const char *prefix, PK11SymKey *key, size_t binlen)
+{
+	chunk_t chunk = chunk_from_symkey(prefix, key);
+	print_chunk(prefix, chunk, binlen);
+        freeanychunk(chunk);
+}
+
+void print_number(const char *prefix, int number)
+{
+	printf("%s = %d%s", prefix, number, crlf);
+}
+
+void print_line(const char *line)
+{
+	fputs(line, stdout);
+	fputs(crlf, stdout);
+}
diff -Naur libreswan-3.12-orig/programs/pluto/cavp_print.h libreswan-3.12/programs/pluto/cavp_print.h
--- libreswan-3.12-orig/programs/pluto/cavp_print.h	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/cavp_print.h	2015-05-06 11:45:32.914301347 -0400
@@ -0,0 +1,23 @@
+/*
+ * Parse CAVP test vectors, for libreswan
+ *
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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.
+ */
+
+void config_number(const char *prefix, int number);
+void config_key(const char *key);
+
+void print_chunk(const char *prefix, chunk_t chunk, size_t binlen);
+void print_symkey(const char *prefix, PK11SymKey *key, size_t binlen);
+void print_number(const char *prefix, int number);
+void print_line(const char *line);
diff -Naur libreswan-3.12-orig/programs/pluto/cavp_stubs.c libreswan-3.12/programs/pluto/cavp_stubs.c
--- libreswan-3.12-orig/programs/pluto/cavp_stubs.c	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/cavp_stubs.c	2015-05-06 11:45:32.915301359 -0400
@@ -0,0 +1,21 @@
+#include <stdlib.h>
+
+#include "constants.h"
+#include "libreswan/passert.h"
+
+/*
+ * Crud to get main to link.
+ */
+libreswan_passert_fail_t libreswan_passert_fail;
+enum kernel_interface kern_interface;
+extern void exit_pluto(int status);
+void exit_pluto(int status UNUSED) { }
+extern void show_setup_plutomain();
+void show_setup_plutomain() { }
+extern char *pluto_listen;
+char *pluto_listen = NULL;
+u_int16_t secctx_attr_type = 0;
+u_int16_t secctx_attr_value = 0;
+bool force_busy = FALSE;
+bool strict_crl_policy = FALSE;
+deltatime_t crl_check_interval = { 0 };
diff -Naur libreswan-3.12-orig/programs/pluto/cbc_test_vectors.c libreswan-3.12/programs/pluto/cbc_test_vectors.c
--- libreswan-3.12-orig/programs/pluto/cbc_test_vectors.c	2015-05-06 11:44:21.562466284 -0400
+++ libreswan-3.12/programs/pluto/cbc_test_vectors.c	2015-05-06 11:45:32.915301359 -0400
@@ -13,6 +13,7 @@
 
 #include "nss.h"
 #include "pk11pub.h"
+#include "crypt_symkey.h"
 
 struct cbc_test_vector {
 	const char *description;
@@ -183,7 +184,7 @@
 	}
 
 	/* Clean up.  */
-	PK11_FreeSymKey(sym_key);
+	free_any_symkey("sym_key", &sym_key);
 
 	DBG(DBG_CRYPT, DBG_log("test_ctr_vector: %s %s",
 			       test->description, ok ? "passed" : "failed"));
diff -Naur libreswan-3.12-orig/programs/pluto/crypt_dh.c libreswan-3.12/programs/pluto/crypt_dh.c
--- libreswan-3.12-orig/programs/pluto/crypt_dh.c	2015-05-06 11:44:21.583466531 -0400
+++ libreswan-3.12/programs/pluto/crypt_dh.c	2015-05-06 11:45:32.917301382 -0400
@@ -57,90 +57,20 @@
 #include "id.h"
 #include "secrets.h"
 #include "keys.h"
-#include "ikev2_prfplus.h"
+#include "crypt_dh.h"
+#include "crypt_symkey.h"
 
 #include <nss.h>
 #include <pk11pub.h>
 #include <keyhi.h>
 #include "lswconf.h"
 
-/* #define PK11_Derive(base, mechanism, param, target, operation, keysize) \
- *	PK11_Derive_lsw(base, mechanism, param, target, operation, keysize)
- */
-
-/* MUST BE THREAD-SAFE */
-static PK11SymKey *pk11_extract_derive_wrapper_lsw(PK11SymKey *base,
-						   CK_EXTRACT_PARAMS bs,
-						   CK_MECHANISM_TYPE target,
-						   CK_ATTRIBUTE_TYPE operation,
-						   int keySize)
-{
-	SECItem param;
-
-	param.data = (unsigned char*)&bs;
-	param.len = sizeof(bs);
-
-	return PK11_Derive_lsw(base, CKM_EXTRACT_KEY_FROM_KEY, &param, target,
-			       operation, keySize);
-}
-
-static CK_MECHANISM_TYPE nss_encryption_mech(
-	const struct encrypt_desc *encrypter)
-{
-	/* the best wey have for "undefined" */
-	CK_MECHANISM_TYPE mechanism = CKM_VENDOR_DEFINED;
-
-	switch (encrypter->common.algo_id) {
-	case OAKLEY_3DES_CBC:
-		mechanism = CKM_DES3_CBC;
-		break;
-#ifdef NOT_YET
-	case OAKLEY_CAST_CBC:
-		mechanism = CKM_CAST5_CBC:
-		break;
-#endif
-	case OAKLEY_AES_CBC:
-		mechanism = CKM_AES_CBC;
-		break;
-	case OAKLEY_CAMELLIA_CBC:
-		mechanism = CKM_CAMELLIA_CBC;
-		break;
-	case OAKLEY_AES_CTR:
-		mechanism = CKM_AES_CTR;
-		break;
-#ifdef NOT_YET
-	case OAKLEY_AES_CCM_8:
-	case OAKLEY_AES_CCM_12:
-	case OAKLEY_AES_CCM_16:
-		mechanism = CKM_AES_CCM;
-		break;
-#endif
-	case OAKLEY_AES_GCM_8:
-	case OAKLEY_AES_GCM_12:
-	case OAKLEY_AES_GCM_16:
-		mechanism = CKM_AES_GCM;
-		break;
-#ifdef NOT_YET
-	case OAKLEY_TWOFISH_CBC:
-		mechanism = CKM_TWOFISH_CBC;
-		break;
-#endif
-	default:
-		loglog(RC_LOG_SERIOUS,
-			"NSS: Unsupported encryption mechanism for %s",
-			strip_prefix(enum_name(&oakley_enc_names,
-				encrypter->common.algo_id), "OAKLEY_"));
-		break;
-	}
-	return mechanism;
-}
-
 /** Compute DH shared secret from our local secret and the peer's public value.
  * We make the leap that the length should be that of the group
  * (see quoted passage at start of ACCEPT_KE).
  */
 /* MUST BE THREAD-SAFE */
-static PK11SymKey *calc_dh_shared(const chunk_t g,	/* converted to SECItem */
+PK11SymKey *calc_dh_shared(const chunk_t g,	/* converted to SECItem */
 				  /*const*/ SECKEYPrivateKey *privk,	/* NSS doesn't do const */
 				  const struct oakley_group_desc *group,
 				  const SECKEYPublicKey *local_pubk)
@@ -214,7 +144,7 @@
 					  CKM_CONCATENATE_DATA_AND_BASE,
 					  CKA_DERIVE, 0);
 		passert(newdhshared != NULL);
-		PK11_FreeSymKey(dhshared);
+		free_any_symkey("dhshared", &dhshared);
 		dhshared = newdhshared;
 		freeanychunk(zeros);
 	} else {
@@ -240,862 +170,6 @@
 	return dhshared;
 }
 
-/* SKEYID for preshared keys.
- * See draft-ietf-ipsec-ike-01.txt 4.1
- */
-
-static PK11SymKey *skeyid_preshared(const chunk_t pss,
-				    const chunk_t ni,
-				    const chunk_t nr,
-				    PK11SymKey *shared,
-				    const struct hash_desc *hasher)
-{
-	struct hmac_ctx ctx;
-
-	passert(hasher != NULL);
-
-	chunk_t nir;
-	unsigned int k;
-	CK_MECHANISM_TYPE mechanism;
-	u_char buf1[HMAC_BUFSIZE * 2], buf2[HMAC_BUFSIZE * 2];
-	chunk_t buf1_chunk, buf2_chunk;
-	PK11SymKey *skeyid;
-
-	DBG(DBG_CRYPT, {
-		    DBG_log("NSS: skeyid inputs (pss+NI+NR+shared-secret) hasher: %s",
-			    hasher->common.name);
-		    DBG_log("shared-secret (pointer in chunk_t): %p", shared);
-		    DBG_dump_chunk("ni: ", ni);
-		    DBG_dump_chunk("nr: ", nr);
-	    });
-
-	/* We need to hmac_init with the concatenation of Ni_b and Nr_b,
-	 * so we have to build a temporary concatentation.
-	 */
-
-	nir.len = ni.len + nr.len;
-	nir.ptr = alloc_bytes(nir.len, "Ni + Nr in skeyid_preshared");
-	memcpy(nir.ptr, ni.ptr, ni.len);
-	memcpy(nir.ptr + ni.len, nr.ptr, nr.len);
-
-	zero(&buf1);
-
-	if (pss.len <= hasher->hash_block_size) {
-		memcpy(buf1, pss.ptr, pss.len);
-	} else {
-		hasher->hash_init(&ctx.hash_ctx);
-		hasher->hash_update(&ctx.hash_ctx, pss.ptr, pss.len);
-		hasher->hash_final(buf1, &ctx.hash_ctx);
-	}
-
-	memcpy(buf2, buf1, hasher->hash_block_size);
-
-	for (k = 0; k < hasher->hash_block_size; k++) {
-		buf1[k] ^= HMAC_IPAD;
-		buf2[k] ^= HMAC_OPAD;
-	}
-
-	/* pfree(nir.ptr); */
-
-	mechanism = nss_key_derivation_mech(hasher);
-	buf1_chunk.ptr = buf1;
-	buf1_chunk.len = hasher->hash_block_size;
-
-	buf2_chunk.ptr = buf2;
-	buf2_chunk.len = hasher->hash_block_size;
-
-	PK11SymKey *tkey4 = pk11_derive_wrapper_lsw(shared,
-						    CKM_CONCATENATE_DATA_AND_BASE, buf1_chunk, CKM_EXTRACT_KEY_FROM_KEY, CKA_DERIVE,
-						    0);
-	/* nss_symkey_log(tkey4, "pss+ipad+shared"); */
-
-	CK_EXTRACT_PARAMS bs = 0;
-	PK11SymKey *tkey5 = pk11_extract_derive_wrapper_lsw(tkey4, bs,
-							    CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-							    hasher->hash_block_size);
-	/* nss_symkey_log(tkey5, "pss+ipad"); */
-
-	PK11SymKey *tkey6 = pk11_derive_wrapper_lsw(tkey5,
-						    CKM_CONCATENATE_BASE_AND_DATA, nir, mechanism, CKA_DERIVE,
-						    0);
-	pfree(nir.ptr);
-	/* nss_symkey_log(tkey6, "pss+ipad+nir"); */
-
-	/* PK11SymKey *tkey1 = pk11_derive_wrapper_lsw(shared, CKM_CONCATENATE_DATA_AND_BASE, buf1_chunk, mechanism, CKA_DERIVE, 0); */
-	PK11SymKey *tkey2 = PK11_Derive_lsw(tkey6, mechanism, NULL,
-					    CKM_CONCATENATE_DATA_AND_BASE,
-					    CKA_DERIVE, 0);
-	/* nss_symkey_log(tkey2, "pss : tkey2"); */
-
-	PK11SymKey *tkey3 = pk11_derive_wrapper_lsw(tkey2,
-						    CKM_CONCATENATE_DATA_AND_BASE, buf2_chunk, mechanism, CKA_DERIVE,
-						    0);
-	skeyid = PK11_Derive_lsw(tkey3, mechanism, NULL,
-				 CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, 0);
-	/* nss_symkey_log(tkey2, "pss : tkey3"); */
-
-	PK11_FreeSymKey(tkey4);
-	PK11_FreeSymKey(tkey5);
-	PK11_FreeSymKey(tkey6);
-	PK11_FreeSymKey(tkey2);
-	PK11_FreeSymKey(tkey3);
-
-	DBG(DBG_CRYPT,
-	    DBG_log("NSS: skeyid in skeyid_preshared() (pointer) %p: ",
-		    skeyid));
-	return skeyid;
-}
-
-/* MUST BE THREAD-SAFE */
-static PK11SymKey *skeyid_digisig(const chunk_t ni,
-			   const chunk_t nr,
-			   /*const*/ PK11SymKey *shared,	/* NSS doesn't do const */
-			   const struct hash_desc *hasher)
-{
-	struct hmac_ctx ctx;
-	chunk_t nir;
-	unsigned int k;
-	CK_MECHANISM_TYPE mechanism;
-	u_char buf1[HMAC_BUFSIZE * 2], buf2[HMAC_BUFSIZE * 2];
-	chunk_t buf1_chunk, buf2_chunk;
-	PK11SymKey *skeyid;
-
-	DBG(DBG_CRYPT, {
-		    DBG_log("skeyid inputs (digi+NI+NR+shared) hasher: %s",
-			    hasher->common.name);
-		    DBG_dump_chunk("ni: ", ni);
-		    DBG_dump_chunk("nr: ", nr);
-	    });
-
-	/* We need to hmac_init with the concatenation of Ni_b and Nr_b,
-	 * so we have to build a temporary concatentation.
-	 */
-	nir.len = ni.len + nr.len;
-	nir.ptr = alloc_bytes(nir.len, "Ni + Nr in skeyid_digisig");
-	memcpy(nir.ptr, ni.ptr, ni.len);
-	memcpy(nir.ptr + ni.len, nr.ptr, nr.len);
-	zero(&buf1);
-	if (nir.len <= hasher->hash_block_size) {
-		memcpy(buf1, nir.ptr, nir.len);
-	} else {
-		hasher->hash_init(&ctx.hash_ctx);
-		hasher->hash_update(&ctx.hash_ctx, nir.ptr, nir.len);
-		hasher->hash_final(buf1, &ctx.hash_ctx);
-	}
-
-	memcpy(buf2, buf1, hasher->hash_block_size);
-
-	for (k = 0; k < hasher->hash_block_size; k++) {
-		buf1[k] ^= HMAC_IPAD;
-		buf2[k] ^= HMAC_OPAD;
-	}
-
-	pfree(nir.ptr);
-	mechanism = nss_key_derivation_mech(hasher);
-	buf1_chunk.ptr = buf1;
-	buf1_chunk.len = hasher->hash_block_size;
-
-	buf2_chunk.ptr = buf2;
-	buf2_chunk.len = hasher->hash_block_size;
-
-	PK11SymKey *tkey1 = pk11_derive_wrapper_lsw(shared,
-						    CKM_CONCATENATE_DATA_AND_BASE, buf1_chunk, mechanism, CKA_DERIVE,
-						    0);
-	PK11SymKey *tkey2 = PK11_Derive_lsw(tkey1, mechanism, NULL,
-					    CKM_CONCATENATE_DATA_AND_BASE,
-					    CKA_DERIVE, 0);
-	PK11SymKey *tkey3 = pk11_derive_wrapper_lsw(tkey2,
-						    CKM_CONCATENATE_DATA_AND_BASE, buf2_chunk, mechanism, CKA_DERIVE,
-						    0);
-	skeyid = PK11_Derive_lsw(tkey3, mechanism, NULL,
-				 CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, 0);
-
-	PK11_FreeSymKey(tkey1);
-	PK11_FreeSymKey(tkey2);
-	PK11_FreeSymKey(tkey3);
-
-	DBG(DBG_CRYPT,
-	    DBG_log("NSS: digisig skeyid pointer: %p", skeyid));
-
-	return skeyid;
-}
-
-/* Generate the SKEYID_* and new IV
- * See draft-ietf-ipsec-ike-01.txt 4.1
- */
-/* MUST BE THREAD-SAFE */
-static void calc_skeyids_iv(struct pcr_skeyid_q *skq,
-			    /*const*/ PK11SymKey *shared,	/* NSS doesn't do const */
-			    const size_t keysize,	/* = st->st_oakley.enckeylen/BITS_PER_BYTE; */
-			    PK11SymKey **skeyid_out,	/* output */
-			    PK11SymKey **skeyid_d_out,	/* output */
-			    PK11SymKey **skeyid_a_out,	/* output */
-			    PK11SymKey **skeyid_e_out,	/* output */
-			    chunk_t *new_iv,	/* output */
-			    PK11SymKey **enc_key_out	/* output */
-			    )
-{
-	oakley_auth_t auth = skq->auth;
-	oakley_hash_t hash = skq->prf_hash;
-	const struct hash_desc *hasher = crypto_get_hasher(hash);
-	chunk_t ni;
-	chunk_t nr;
-	chunk_t gi;
-	chunk_t gr;
-	chunk_t icookie;
-	chunk_t rcookie;
-	PK11SymKey
-		*skeyid,
-		*skeyid_d,
-		*skeyid_a,
-		*skeyid_e,
-		*enc_key;
-	const struct encrypt_desc *encrypter = skq->encrypter;
-
-	/* this doesn't allocate any memory */
-	setchunk_from_wire(gi, skq, &skq->gi);
-	setchunk_from_wire(gr, skq, &skq->gr);
-	setchunk_from_wire(ni, skq, &skq->ni);
-	setchunk_from_wire(nr, skq, &skq->nr);
-	setchunk_from_wire(icookie, skq, &skq->icookie);
-	setchunk_from_wire(rcookie, skq, &skq->rcookie);
-
-	/* Generate the SKEYID */
-	switch (auth) {
-	case OAKLEY_PRESHARED_KEY:
-		{
-			chunk_t pss;
-
-			setchunk_from_wire(pss, skq, &skq->pss);
-			skeyid = skeyid_preshared(pss, ni, nr, shared, hasher);
-		}
-		break;
-
-	case OAKLEY_RSA_SIG:
-		skeyid = skeyid_digisig(ni, nr, shared, hasher);
-		break;
-
-	/* Not implemented */
-	case OAKLEY_DSS_SIG:
-	case OAKLEY_RSA_ENC:
-	case OAKLEY_RSA_REVISED_MODE:
-	case OAKLEY_ECDSA_P256:
-	case OAKLEY_ECDSA_P384:
-	case OAKLEY_ECDSA_P521:
-	default:
-		bad_case(auth);
-	}
-
-	/* generate SKEYID_* from SKEYID */
-	{
-
-		chunk_t hmac_opad, hmac_ipad, hmac_pad, hmac_zerobyte,
-			hmac_val1, hmac_val2;
-		CK_OBJECT_HANDLE keyhandle;
-		SECItem param, param1;
-
-		hmac_opad = hmac_pads(HMAC_OPAD, hasher->hash_block_size);
-		hmac_ipad = hmac_pads(HMAC_IPAD, hasher->hash_block_size);
-		hmac_pad  = hmac_pads(0x00,
-				      hasher->hash_block_size -
-				      hasher->hash_digest_len);
-		hmac_zerobyte = hmac_pads(0x00, 1);
-		hmac_val1 = hmac_pads(0x01, 1);
-		hmac_val2 = hmac_pads(0x02, 1);
-
-		DBG(DBG_CRYPT, DBG_log("NSS: Started key computation"));
-
-		/*Deriving SKEYID_d = hmac_xxx(SKEYID, g^xy | CKY-I | CKY-R | 0) */
-		PK11SymKey *tkey1 = pk11_derive_wrapper_lsw(skeyid,
-							    CKM_CONCATENATE_BASE_AND_DATA,
-							    hmac_pad,
-							    CKM_XOR_BASE_AND_DATA,
-							    CKA_DERIVE,
-							    hasher->hash_block_size);
-
-		passert(tkey1 != NULL);
-
-		/*DBG(DBG_CRYPT, DBG_log("Started key computation: 1, length=%d", PK11_GetKeyLength(tkey1)));
-		 * nss_symkey_log(tkey1, "1");
-		 */
-
-		PK11SymKey *tkey2 = pk11_derive_wrapper_lsw(tkey1,
-							    CKM_XOR_BASE_AND_DATA,
-							    hmac_ipad,
-							    CKM_CONCATENATE_BASE_AND_KEY,
-							    CKA_DERIVE,
-							    0);
-
-		passert(tkey2 != NULL);
-
-		keyhandle = PK11_GetSymKeyHandle(shared);
-		param.data = (unsigned char *) &keyhandle;
-		param.len = sizeof(keyhandle);
-		DBG(DBG_CRYPT,
-		    DBG_log("NSS: dh shared param len=%d", param.len));
-
-		PK11SymKey *tkey3 = PK11_Derive_lsw(tkey2,
-						    CKM_CONCATENATE_BASE_AND_KEY,
-						    &param,
-						    CKM_CONCATENATE_BASE_AND_DATA,
-						    CKA_DERIVE,
-						    0);
-		passert(tkey3 != NULL);
-
-		PK11SymKey *tkey4 = pk11_derive_wrapper_lsw(tkey3,
-							    CKM_CONCATENATE_BASE_AND_DATA,
-							    icookie,
-							    CKM_CONCATENATE_BASE_AND_DATA,
-							    CKA_DERIVE,
-							    0);
-		passert(tkey4 != NULL);
-
-		PK11SymKey *tkey5 = pk11_derive_wrapper_lsw(tkey4,
-							    CKM_CONCATENATE_BASE_AND_DATA,
-							    rcookie,
-							    CKM_CONCATENATE_BASE_AND_DATA,
-							    CKA_DERIVE,
-							    0);
-
-		passert(tkey5 != NULL);
-
-		PK11SymKey *tkey6 = pk11_derive_wrapper_lsw(tkey5,
-							    CKM_CONCATENATE_BASE_AND_DATA,
-							    hmac_zerobyte,
-							    nss_key_derivation_mech(hasher),
-							    CKA_DERIVE,
-							    0);
-
-		passert(tkey6 != NULL);
-
-		PK11SymKey *tkey7 = PK11_Derive_lsw(tkey6,
-						    nss_key_derivation_mech(hasher),
-						    NULL,
-						    CKM_CONCATENATE_BASE_AND_DATA,
-						    CKA_DERIVE,
-						    0);
-		passert(tkey7 != NULL);
-
-		PK11SymKey *tkey8 = pk11_derive_wrapper_lsw(tkey1,
-							    CKM_XOR_BASE_AND_DATA,
-							    hmac_opad,
-							    CKM_CONCATENATE_BASE_AND_KEY,
-							    CKA_DERIVE,
-							    0);
-		passert(tkey8 != NULL);
-
-		keyhandle = PK11_GetSymKeyHandle(tkey7);
-		param.data = (unsigned char*)&keyhandle;
-		param.len = sizeof(keyhandle);
-
-		PK11SymKey *tkey9 = PK11_Derive_lsw(tkey8,
-						    CKM_CONCATENATE_BASE_AND_KEY,
-						    &param,
-						    nss_key_derivation_mech(hasher),
-						    CKA_DERIVE,
-						    0);
-		passert(tkey9 != NULL);
-
-		skeyid_d = PK11_Derive_lsw(tkey9,
-					   nss_key_derivation_mech(hasher),
-					   NULL,
-					   CKM_CONCATENATE_BASE_AND_DATA,
-					   CKA_DERIVE,
-					   0);
-		passert(skeyid_d != NULL);
-		/* nss_symkey_log(skeyid_d, "skeyid_d"); */
-		/*****End of SKEYID_d derivation***************************************/
-
-		/*Deriving SKEYID_a = hmac_xxx(SKEYID, SKEYID_d | g^xy | CKY-I | CKY-R | 1)*/
-		keyhandle = PK11_GetSymKeyHandle(skeyid_d);
-		param.data = (unsigned char*)&keyhandle;
-		param.len = sizeof(keyhandle);
-
-		PK11SymKey *tkey10 = PK11_Derive_lsw(tkey2,
-						     CKM_CONCATENATE_BASE_AND_KEY,
-						     &param,
-						     CKM_CONCATENATE_BASE_AND_KEY,
-						     CKA_DERIVE,
-						     0);
-		passert(tkey10 != NULL);
-
-		keyhandle = PK11_GetSymKeyHandle(shared);
-		param.data = (unsigned char*)&keyhandle;
-		param.len = sizeof(keyhandle);
-
-		PK11SymKey *tkey11 = PK11_Derive_lsw(tkey10,
-						     CKM_CONCATENATE_BASE_AND_KEY,
-						     &param,
-						     CKM_CONCATENATE_BASE_AND_DATA,
-						     CKA_DERIVE,
-						     0);
-		passert(tkey11 != NULL);
-
-		PK11SymKey *tkey12 = pk11_derive_wrapper_lsw(tkey11,
-							     CKM_CONCATENATE_BASE_AND_DATA,
-							     icookie, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-							     0);
-		passert(tkey12 != NULL);
-
-		PK11SymKey *tkey13 = pk11_derive_wrapper_lsw(tkey12,
-							     CKM_CONCATENATE_BASE_AND_DATA,
-							     rcookie,
-							     CKM_CONCATENATE_BASE_AND_DATA,
-							     CKA_DERIVE,
-							     0);
-		passert(tkey13 != NULL);
-
-		PK11SymKey *tkey14 = pk11_derive_wrapper_lsw(tkey13,
-							     CKM_CONCATENATE_BASE_AND_DATA,
-							     hmac_val1,
-							     nss_key_derivation_mech(hasher),
-							     CKA_DERIVE,
-							     0);
-		passert(tkey14 != NULL);
-
-		PK11SymKey *tkey15 = PK11_Derive_lsw(tkey14,
-						     nss_key_derivation_mech(hasher),
-						     NULL,
-						     CKM_CONCATENATE_BASE_AND_DATA,
-						     CKA_DERIVE,
-						     0);
-		passert(tkey15 != NULL);
-
-		keyhandle = PK11_GetSymKeyHandle(tkey15);
-		param.data = (unsigned char*)&keyhandle;
-		param.len = sizeof(keyhandle);
-
-		PK11SymKey *tkey16 = PK11_Derive_lsw(tkey8,
-						     CKM_CONCATENATE_BASE_AND_KEY, &param,
-						     nss_key_derivation_mech(hasher),
-						     CKA_DERIVE,
-						     0);
-		passert(tkey16 != NULL);
-
-		skeyid_a = PK11_Derive_lsw(tkey16,
-					   nss_key_derivation_mech(hasher),
-					   NULL,
-					   CKM_CONCATENATE_BASE_AND_DATA,
-					   CKA_DERIVE,
-					   0);
-		passert(skeyid_a != NULL);
-		/* nss_symkey_log(skeyid_a, "skeyid_a"); */
-		/*****End of SKEYID_a derivation***************************************/
-
-		/*Deriving SKEYID_e = prf(SKEYID, SKEYID_a | g^xy | CKY-I | CKY-R | 2)*/
-		keyhandle = PK11_GetSymKeyHandle(skeyid_a);
-		param.data = (unsigned char*)&keyhandle;
-		param.len = sizeof(keyhandle);
-
-		PK11SymKey *tkey17 = PK11_Derive_lsw(tkey2,
-						     CKM_CONCATENATE_BASE_AND_KEY, &param, CKM_CONCATENATE_BASE_AND_KEY, CKA_DERIVE,
-						     0);
-		passert(tkey17 != NULL);
-
-		keyhandle = PK11_GetSymKeyHandle(shared);
-		param.data = (unsigned char*)&keyhandle;
-		param.len = sizeof(keyhandle);
-
-		PK11SymKey *tkey18 = PK11_Derive_lsw(tkey17,
-						     CKM_CONCATENATE_BASE_AND_KEY, &param, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-						     0);
-		passert(tkey18 != NULL);
-
-		PK11SymKey *tkey19 = pk11_derive_wrapper_lsw(tkey18,
-							     CKM_CONCATENATE_BASE_AND_DATA,
-							     icookie, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-							     0);
-		passert(tkey19 != NULL);
-
-		PK11SymKey *tkey20 = pk11_derive_wrapper_lsw(tkey19,
-							     CKM_CONCATENATE_BASE_AND_DATA,
-							     rcookie, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-							     0);
-		passert(tkey20 != NULL);
-
-		PK11SymKey *tkey21 = pk11_derive_wrapper_lsw(tkey20,
-							     CKM_CONCATENATE_BASE_AND_DATA,
-							     hmac_val2,
-							     nss_key_derivation_mech(
-								     hasher), CKA_DERIVE,
-							     0);
-		passert(tkey21 != NULL);
-
-		PK11SymKey *tkey22 = PK11_Derive_lsw(tkey21, nss_key_derivation_mech(
-							     hasher), NULL, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-						     0);
-		passert(tkey22 != NULL);
-
-		keyhandle = PK11_GetSymKeyHandle(tkey22);
-		param.data = (unsigned char*)&keyhandle;
-		param.len = sizeof(keyhandle);
-
-		PK11SymKey *tkey23 = PK11_Derive_lsw(tkey8,
-						     CKM_CONCATENATE_BASE_AND_KEY, &param,
-						     nss_key_derivation_mech(
-							     hasher), CKA_DERIVE,
-						     0);
-		passert(tkey23 != NULL);
-
-		DBG(DBG_CRYPT, DBG_log("NSS: enc keysize=%d", (int)keysize));
-		/* Deriving encryption key from SKEYID_e */
-		/* Oakley Keying Material
-		 * Derived from Skeyid_e: if it is not big enough, generate more
-		 * using the PRF.
-		 * See RFC 2409 "IKE" Appendix B
-		 */
-
-		CK_EXTRACT_PARAMS bitstart = 0;
-		param1.data = (unsigned char*)&bitstart;
-		param1.len = sizeof(bitstart);
-
-		if (keysize <= hasher->hash_digest_len) {
-			skeyid_e = PK11_Derive_lsw(tkey23,
-						   nss_key_derivation_mech(hasher),
-						   NULL,
-						   CKM_EXTRACT_KEY_FROM_KEY,	/* note */
-						   CKA_DERIVE, 0);
-			passert(skeyid_e != NULL);
-			/* nss_symkey_log(skeyid_e, "skeyid_e"); */
-
-			enc_key = PK11_DeriveWithFlags(skeyid_e,
-						       CKM_EXTRACT_KEY_FROM_KEY, &param1,
-						       nss_encryption_mech(encrypter),
-						       CKA_FLAGS_ONLY, keysize,
-						       CKF_ENCRYPT | CKF_DECRYPT);
-			passert(enc_key != NULL);
-
-			/* nss_symkey_log(enc_key, "enc_key"); */
-		} else {
-			size_t i = 0;
-			PK11SymKey *keymat;
-
-			skeyid_e = PK11_Derive_lsw(tkey23,
-						   nss_key_derivation_mech(hasher),
-						   NULL,
-						   CKM_CONCATENATE_BASE_AND_DATA,	/* note */
-						   CKA_DERIVE, 0);
-			passert(skeyid_e != NULL);
-			/* nss_symkey_log(skeyid_e, "skeyid_e"); */
-
-			PK11SymKey *tkey25 = pk11_derive_wrapper_lsw(skeyid_e,
-								     CKM_CONCATENATE_BASE_AND_DATA,
-								     hmac_pad, CKM_XOR_BASE_AND_DATA, CKA_DERIVE,
-								     hasher->hash_block_size);
-			passert(tkey25 != NULL);
-
-			PK11SymKey *tkey26 = pk11_derive_wrapper_lsw(tkey25,
-								     CKM_XOR_BASE_AND_DATA,
-								     hmac_ipad, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-								     0);
-			passert(tkey26 != NULL);
-
-			PK11SymKey *tkey27 = pk11_derive_wrapper_lsw(tkey26,
-								     CKM_CONCATENATE_BASE_AND_DATA,
-								     hmac_zerobyte,
-								     nss_key_derivation_mech(
-									     hasher), CKA_DERIVE,
-								     0);
-			passert(tkey27 != NULL);
-
-			PK11SymKey *tkey28 = PK11_Derive_lsw(tkey27, nss_key_derivation_mech(
-								     hasher), NULL,
-							     CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-							     0);
-			passert(tkey28 != NULL);
-
-			PK11SymKey *tkey29 = pk11_derive_wrapper_lsw(tkey25,
-								     CKM_XOR_BASE_AND_DATA,
-								     hmac_opad, CKM_CONCATENATE_BASE_AND_KEY, CKA_DERIVE,
-								     0);
-			passert(tkey29 != NULL);
-
-			keyhandle = PK11_GetSymKeyHandle(tkey28);
-			param.data = (unsigned char*)&keyhandle;
-			param.len = sizeof(keyhandle);
-
-			PK11SymKey *tkey30 = PK11_Derive_lsw(tkey29,
-							     CKM_CONCATENATE_BASE_AND_KEY, &param,
-							     nss_key_derivation_mech(
-								     hasher), CKA_DERIVE,
-							     0);
-			passert(tkey30 != NULL);
-
-			PK11SymKey *tkey31 = PK11_Derive_lsw(tkey30, nss_key_derivation_mech(
-								     hasher), NULL, CKM_CONCATENATE_BASE_AND_KEY, CKA_DERIVE,
-							     0);
-			passert(tkey31 != NULL);
-
-			keymat = tkey31;
-
-			i += hasher->hash_digest_len;
-
-			PK11SymKey *tkey32 = pk11_derive_wrapper_lsw(skeyid_e,
-								     CKM_CONCATENATE_BASE_AND_DATA,
-								     hmac_pad, CKM_XOR_BASE_AND_DATA, CKA_DERIVE,
-								     hasher->hash_block_size);
-			passert(tkey32 != NULL);
-
-			PK11SymKey *tkey33 = pk11_derive_wrapper_lsw(tkey32,
-								     CKM_XOR_BASE_AND_DATA,
-								     hmac_ipad, CKM_CONCATENATE_BASE_AND_KEY, CKA_DERIVE,
-								     0);
-			passert(tkey33 != NULL);
-
-			PK11SymKey *tkey36 = pk11_derive_wrapper_lsw(tkey32,
-								     CKM_XOR_BASE_AND_DATA,
-								     hmac_opad, CKM_CONCATENATE_BASE_AND_KEY, CKA_DERIVE,
-								     0);
-			passert(tkey36 != NULL);
-
-			for (;; ) {
-
-				keyhandle = PK11_GetSymKeyHandle(tkey31);
-				param.data = (unsigned char*)&keyhandle;
-				param.len = sizeof(keyhandle);
-
-				PK11SymKey *tkey34 = PK11_Derive_lsw(tkey33,
-								     CKM_CONCATENATE_BASE_AND_KEY, &param,
-								     nss_key_derivation_mech(
-									     hasher), CKA_DERIVE,
-								     0);
-				passert(tkey34 != NULL);
-
-				PK11SymKey *tkey35 = PK11_Derive_lsw(tkey34, nss_key_derivation_mech(
-									     hasher), NULL,
-								     CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-								     0);
-				passert(tkey35 != NULL);
-
-				keyhandle = PK11_GetSymKeyHandle(tkey35);
-				param.data = (unsigned char*)&keyhandle;
-				param.len = sizeof(keyhandle);
-
-				PK11SymKey *tkey37 = PK11_Derive_lsw(tkey36,
-								     CKM_CONCATENATE_BASE_AND_KEY, &param,
-								     nss_key_derivation_mech(
-									     hasher), CKA_DERIVE,
-								     0);
-				passert(tkey37 != NULL);
-
-				PK11SymKey *tkey38 = PK11_Derive_lsw(tkey37, nss_key_derivation_mech(
-									     hasher), NULL, CKM_CONCATENATE_BASE_AND_KEY, CKA_DERIVE,
-								     0);
-				passert(tkey38 != NULL);
-
-				i += hasher->hash_digest_len;
-
-				if (i >= keysize ) {
-
-					/*concatenating K1 and K2 */
-					keyhandle =
-						PK11_GetSymKeyHandle(tkey38);
-					param.data =
-						(unsigned char*)&keyhandle;
-					param.len = sizeof(keyhandle);
-
-					PK11SymKey *tkey39 = PK11_Derive_lsw(
-						keymat,
-						CKM_CONCATENATE_BASE_AND_KEY,
-						&param,
-						CKM_EXTRACT_KEY_FROM_KEY,
-						CKA_DERIVE, 0);
-					passert(tkey39 != NULL);
-
-					enc_key = PK11_DeriveWithFlags(tkey39,
-								       CKM_EXTRACT_KEY_FROM_KEY, &param1,
-								       nss_encryption_mech(encrypter),
-								       CKA_FLAGS_ONLY, /*0*/ keysize,
-								       CKF_ENCRYPT | CKF_DECRYPT);
-
-					/* nss_symkey_log(enc_key, "enc_key"); */
-					passert(enc_key != NULL);
-
-					PK11_FreeSymKey(tkey25);
-					PK11_FreeSymKey(tkey26);
-					PK11_FreeSymKey(tkey27);
-					PK11_FreeSymKey(tkey28);
-					PK11_FreeSymKey(tkey29);
-					PK11_FreeSymKey(tkey30);
-					PK11_FreeSymKey(tkey31);
-					PK11_FreeSymKey(tkey32);
-					PK11_FreeSymKey(tkey33);
-					PK11_FreeSymKey(tkey34);
-					PK11_FreeSymKey(tkey35);
-					PK11_FreeSymKey(tkey36);
-					PK11_FreeSymKey(tkey37);
-					PK11_FreeSymKey(tkey38);
-					PK11_FreeSymKey(tkey39);
-					PK11_FreeSymKey(keymat);
-
-					DBG(DBG_CRYPT,
-					    DBG_log(
-						    "NSS: Freed 25-39 symkeys"));
-					break;
-				} else {
-
-					keyhandle =
-						PK11_GetSymKeyHandle(tkey38);
-					param.data =
-						(unsigned char*)&keyhandle;
-					param.len = sizeof(keyhandle);
-
-					PK11SymKey *tkey39 = PK11_Derive_lsw(
-						keymat,
-						CKM_CONCATENATE_BASE_AND_KEY,
-						&param,
-						CKM_CONCATENATE_BASE_AND_KEY,
-						CKA_DERIVE, 0);
-					passert(tkey39 != NULL);
-
-					keymat = tkey39;
-					PK11_FreeSymKey(tkey31);
-					tkey31 = tkey38;
-					PK11_FreeSymKey(tkey34);
-					PK11_FreeSymKey(tkey35);
-					PK11_FreeSymKey(tkey37);
-
-					DBG(DBG_CRYPT,
-					    DBG_log(
-						    "NSS: Freed symkeys 31 34 35 37"));
-				}
-			}       /*end for*/
-		}               /*end else skeyid_e */
-
-		/*****End of SKEYID_e and encryption key derivation***************************************/
-
-		/********Saving pointers of all derived keys**********************************************/
-		*skeyid_out = skeyid;
-		*skeyid_d_out = skeyid_d;
-		*skeyid_a_out = skeyid_a;
-		*skeyid_e_out = skeyid_e;
-		*enc_key_out = enc_key;
-
-		DBG(DBG_CRYPT, DBG_log("NSS: pointers skeyid_d %p,  skeyid_a %p,  skeyid_e %p,  enc_key %p",
-			skeyid_d, skeyid_a, skeyid_e, enc_key));
-
-
-		/*****Freeing tmp keys***************************************/
-		PK11_FreeSymKey(tkey1);
-		PK11_FreeSymKey(tkey2);
-		PK11_FreeSymKey(tkey3);
-		PK11_FreeSymKey(tkey4);
-		PK11_FreeSymKey(tkey5);
-		PK11_FreeSymKey(tkey6);
-		PK11_FreeSymKey(tkey7);
-		PK11_FreeSymKey(tkey8);
-		PK11_FreeSymKey(tkey9);
-		PK11_FreeSymKey(tkey10);
-		PK11_FreeSymKey(tkey11);
-		PK11_FreeSymKey(tkey12);
-		PK11_FreeSymKey(tkey13);
-		PK11_FreeSymKey(tkey14);
-		PK11_FreeSymKey(tkey15);
-		PK11_FreeSymKey(tkey16);
-		PK11_FreeSymKey(tkey17);
-		PK11_FreeSymKey(tkey18);
-		PK11_FreeSymKey(tkey19);
-		PK11_FreeSymKey(tkey20);
-		PK11_FreeSymKey(tkey21);
-		PK11_FreeSymKey(tkey22);
-		PK11_FreeSymKey(tkey23);
-
-		DBG(DBG_CRYPT, DBG_log("NSS: Freed symkeys 1-23"));
-
-		freeanychunk(hmac_opad);
-		freeanychunk(hmac_ipad);
-		freeanychunk(hmac_pad);
-		freeanychunk(hmac_zerobyte);
-		freeanychunk(hmac_val1);
-		freeanychunk(hmac_val2);
-		DBG(DBG_CRYPT, DBG_log("NSS: Freed padding chunks"));
-	}
-
-	/* generate IV */
-	{
-		union hash_ctx hash_ctx;
-
-		new_iv->len = hasher->hash_digest_len;
-		new_iv->ptr = alloc_bytes(new_iv->len, "calculated new iv");
-
-		DBG(DBG_CRYPT, {
-			    DBG_dump_chunk("DH_i:", gi);
-			    DBG_dump_chunk("DH_r:", gr);
-		    });
-		hasher->hash_init(&hash_ctx);
-		hasher->hash_update(&hash_ctx, gi.ptr, gi.len);
-		hasher->hash_update(&hash_ctx, gr.ptr, gr.len);
-		hasher->hash_final(new_iv->ptr, &hash_ctx);
-		DBG(DBG_CRYPT, DBG_log("end of IV generation"));
-	}
-}
-
-/* MUST BE THREAD-SAFE */
-void calc_dh_iv(struct pluto_crypto_req *r)
-{
-	struct pcr_skeyid_r *skr = &r->pcr_d.dhr;
-	struct pcr_skeyid_q dhq;
-	const struct oakley_group_desc *group;
-	PK11SymKey *shared;
-	chunk_t g;
-	SECKEYPrivateKey *ltsecret;
-	PK11SymKey
-		*skeyid,
-		*skeyid_d,
-		*skeyid_a,
-		*skeyid_e,
-		*enc_key;
-	chunk_t new_iv;
-	SECKEYPublicKey *pubk;
-
-	/* copy the request, since the reply will re-use the memory of the r->pcr_d.dhq */
-	memcpy(&dhq, &r->pcr_d.dhq, sizeof(r->pcr_d.dhq));
-
-	/* clear out the reply */
-	zero(skr);
-	INIT_WIRE_ARENA(*skr);
-
-	group = lookup_group(dhq.oakley_group);
-	passert(group != NULL);
-
-	ltsecret = dhq.secret;
-	pubk = dhq.pubk;
-
-	/* now calculate the (g^x)(g^y) ---
-	 * need gi on responder, gr on initiator
-	 */
-
-	setchunk_from_wire(g, &dhq, dhq.role == O_RESPONDER ? &dhq.gi : &dhq.gr);
-
-	DBG(DBG_CRYPT,
-	    DBG_dump_chunk("peer's g: ", g));
-
-	shared = calc_dh_shared(g, ltsecret, group, pubk);
-
-	zero(&new_iv);
-
-	/* okay, so now calculate IV */
-	calc_skeyids_iv(&dhq,
-			shared,
-			dhq.key_size,
-			&skeyid,
-			&skeyid_d,
-			&skeyid_a,
-			&skeyid_e,
-			&new_iv,
-			&enc_key);
-
-	skr->shared = shared;
-	skr->skeyid = skeyid;
-	skr->skeyid_d = skeyid_d;
-	skr->skeyid_a = skeyid_a;
-	skr->skeyid_e = skeyid_e;
-	skr->enc_key = enc_key;
-
-
-	WIRE_CLONE_CHUNK(*skr, new_iv, new_iv);
-	freeanychunk(new_iv);
-}
 
 /* MUST BE THREAD-SAFE */
 void calc_dh(struct pluto_crypto_req *r)
@@ -1128,496 +202,3 @@
 
 	skr->shared = calc_dh_shared(g, ltsecret, group, pubk);
 }
-
-static chunk_t chunk_from_symkey(const char *name, PK11SymKey *source_key,
-				 size_t next_bit, size_t byte_size)
-{
-	if (byte_size == 0) {
-		DBG(DBG_CRYPT, DBG_log("chunk_from_symkey: %s: zero size", name));
-		return empty_chunk;
-	}
-	CK_EXTRACT_PARAMS bs = next_bit;
-	SECItem param = { .data = (unsigned char*)&bs, .len = sizeof(bs) };
-	PK11SymKey *sym_key = PK11_DeriveWithFlags(source_key,
-						   CKM_EXTRACT_KEY_FROM_KEY,
-						   &param,
-						   CKM_VENDOR_DEFINED,
-						   CKA_FLAGS_ONLY, byte_size, 0);
-	if (sym_key == NULL) {
-		loglog(RC_LOG_SERIOUS, "NSS: PK11_DeriveWithFlags failed while generating %s", name);
-		return empty_chunk;
-	}
-	SECStatus s = PK11_ExtractKeyValue(sym_key);
-	if (s != SECSuccess) {
-		loglog(RC_LOG_SERIOUS, "NSS: PK11_ExtractKeyValue failed while generating %s", name);
-		return empty_chunk;	
-	}
-	/* Internal structure address, do not free.  */
-	SECItem *data = PK11_GetKeyData(sym_key);
-	if (data == NULL) {
-		loglog(RC_LOG_SERIOUS, "NSS: PK11_GetKeyData failed while generating %s", name);
-		return empty_chunk;
-	}
-	DBG(DBG_CRYPT,
-	    DBG_log("chunk_from_symkey: %s: extracted len %d bytes at %p",
-		    name, data->len, data->data));
-	if (data->len != byte_size) {
-		loglog(RC_LOG_SERIOUS, "NSS: PK11_GetKeyData returned wrong number of bytes while generating %s", name);
-		return empty_chunk;
-	}
-	chunk_t chunk;
-	clonetochunk(chunk, data->data, data->len, name);
-	DBG(DBG_CRYPT, DBG_dump_chunk(name, chunk));
-	PK11_FreeSymKey(sym_key);
-	return chunk;
-}
-
-/*
- * IKEv2 - RFC4306 2.14 SKEYSEED - calculation.
- */
-
-/* MUST BE THREAD-SAFE */
-static void calc_skeyseed_v2(struct pcr_skeyid_q *skq,
-			     PK11SymKey *shared,
-			     const size_t key_size,
-			     const size_t salt_size,
-			     PK11SymKey **skeyseed_out,
-			     PK11SymKey **SK_d_out,
-			     PK11SymKey **SK_ai_out,
-			     PK11SymKey **SK_ar_out,
-			     PK11SymKey **SK_ei_out,
-			     PK11SymKey **SK_er_out,
-			     PK11SymKey **SK_pi_out,
-			     PK11SymKey **SK_pr_out,
-			     chunk_t *initiator_salt_out,
-			     chunk_t *responder_salt_out
-			     )
-{
-	struct v2prf_stuff vpss;
-
-	chunk_t hmac_opad, hmac_ipad, hmac_pad_prf;
-	/* chunk_t hmac_pad_integ, hmac_zerobyte, hmac_val1, hmac_val2; */
-
-	CK_OBJECT_HANDLE keyhandle;
-	SECItem param, param1;
-	DBG(DBG_CRYPT, DBG_log("NSS: Started key computation"));
-
-	PK11SymKey
-		*skeyseed_k,
-		*SK_d_k,
-		*SK_ai_k,
-		*SK_ar_k,
-		*SK_ei_k,
-		*SK_er_k,
-		*SK_pi_k,
-		*SK_pr_k;
-	chunk_t initiator_salt;
-	chunk_t responder_salt;
-
-	zero(&vpss);
-
-	/* this doesn't take any memory, it's just moving pointers around */
-	setchunk_from_wire(vpss.ni, skq, &skq->ni);
-	setchunk_from_wire(vpss.nr, skq, &skq->nr);
-	setchunk_from_wire(vpss.spii, skq, &skq->icookie);
-	setchunk_from_wire(vpss.spir, skq, &skq->rcookie);
-
-	DBG(DBG_CONTROLMORE,
-	    DBG_log("calculating skeyseed using prf=%s integ=%s cipherkey-size=%zu salt-size=%zu",
-		    enum_name(&ikev2_trans_type_prf_names, skq->prf_hash),
-		    enum_name(&ikev2_trans_type_integ_names, skq->integ_hash),
-		    key_size, salt_size));
-
-	const struct hash_desc *prf_hasher = (struct hash_desc *)
-		ikev2_alg_find(IKE_ALG_HASH, skq->prf_hash);
-	passert(prf_hasher != NULL);
-
-	const struct encrypt_desc *encrypter = skq->encrypter;
-	passert(encrypter != NULL);
-
-	hmac_opad = hmac_pads(HMAC_OPAD, prf_hasher->hash_block_size);
-	hmac_ipad = hmac_pads(HMAC_IPAD, prf_hasher->hash_block_size);
-	hmac_pad_prf = hmac_pads(0x00,
-				 prf_hasher->hash_block_size -
-				 prf_hasher->hash_digest_len);
-
-	/* generate SKEYSEED from key=(Ni|Nr), hash of shared */
-	skeyseed_k = skeyid_digisig(vpss.ni, vpss.nr, shared, prf_hasher);
-	passert(skeyseed_k != NULL);
-
-	/* now we have to generate the keys for everything */
-	{
-		/* need to know how many bits to generate */
-		/* SK_d needs PRF hasher key bytes */
-		/* SK_p needs PRF hasher*2 key bytes */
-		/* SK_e needs key_size*2 key bytes */
-		/* ..._salt needs salt_size*2 bytes */
-		/* SK_a needs integ's key size*2 bytes */
-
-		int skd_bytes = prf_hasher->hash_key_size;
-		int skp_bytes = prf_hasher->hash_key_size;
-		const struct hash_desc *integ_hasher =
-			(struct hash_desc *)ikev2_alg_find(IKE_ALG_INTEG, skq->integ_hash);
-		int integ_size = integ_hasher != NULL ? integ_hasher->hash_key_size : 0;
-		size_t total_keysize = skd_bytes + 2*skp_bytes + 2*key_size + 2*salt_size + 2*integ_size;
-		DBG(DBG_CRYPT,
-		    DBG_log("calc_skeyseed_v2: %zd = %d(d) + 2*%d(p) + 2*%zd(key) + 2*%zd(salt) + 2*%d(integ) bytes",
-			    total_keysize, skd_bytes, skp_bytes, key_size, salt_size, integ_size));
-		vpss.counter[0] = 0x01;
-		vpss.t.len = 0;
-
-		DBG(DBG_CRYPT, {
-			    DBG_log("PRF+ input");
-			    DBG_dump_chunk("Ni", vpss.ni);
-			    DBG_dump_chunk("Nr", vpss.nr);
-			    DBG_dump_chunk("SPIi", vpss.spii);
-			    DBG_dump_chunk("SPIr", vpss.spir);
-			    DBG_log("Total keysize needed %zd",
-				    total_keysize);
-		    });
-
-		PK11SymKey *finalkey = NULL;
-		PK11SymKey *tkey11 = NULL;
-		PK11SymKey *tkey1 = pk11_derive_wrapper_lsw(skeyseed_k,
-							    CKM_CONCATENATE_BASE_AND_DATA,
-							    hmac_pad_prf, CKM_XOR_BASE_AND_DATA, CKA_DERIVE,
-							    prf_hasher->hash_block_size);
-		passert(tkey1 != NULL);
-
-		for (;; ) {
-			PK11SymKey *tkey3 = NULL;
-
-			if (vpss.counter[0] == 0x01) {
-				PK11SymKey *tkey2 = pk11_derive_wrapper_lsw(
-					tkey1, CKM_XOR_BASE_AND_DATA,
-					hmac_ipad,
-					CKM_CONCATENATE_BASE_AND_DATA,
-					CKA_DERIVE,
-					0);
-				passert(tkey2 != NULL);
-
-				tkey3 = pk11_derive_wrapper_lsw(tkey2,
-								CKM_CONCATENATE_BASE_AND_DATA,
-								vpss.ni, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-								0);
-				PK11_FreeSymKey(tkey2);
-			} else {
-				PK11SymKey *tkey2 = pk11_derive_wrapper_lsw(
-					tkey1, CKM_XOR_BASE_AND_DATA,
-					hmac_ipad,
-					CKM_CONCATENATE_BASE_AND_KEY,
-					CKA_DERIVE,
-					0);
-				passert(tkey2 != NULL);
-
-				keyhandle = PK11_GetSymKeyHandle(tkey11);
-				param.data = (unsigned char*)&keyhandle;
-				param.len = sizeof(keyhandle);
-
-				PK11SymKey *tkey12 = PK11_Derive_lsw(tkey2,
-								     CKM_CONCATENATE_BASE_AND_KEY,
-								     &param, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-								     0);
-				passert(tkey12 != NULL);
-
-				tkey3 = pk11_derive_wrapper_lsw(tkey12,
-								CKM_CONCATENATE_BASE_AND_DATA,
-								vpss.ni, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-								0);
-				PK11_FreeSymKey(tkey2);
-				PK11_FreeSymKey(tkey11);
-				PK11_FreeSymKey(tkey12);
-			}
-
-			passert(tkey3 != NULL);
-
-			PK11SymKey *tkey4 = pk11_derive_wrapper_lsw(tkey3,
-								    CKM_CONCATENATE_BASE_AND_DATA,
-								    vpss.nr,
-								    CKM_CONCATENATE_BASE_AND_DATA,
-								    CKA_DERIVE,
-								    0);
-			passert(tkey4 != NULL);
-
-			PK11SymKey *tkey5 = pk11_derive_wrapper_lsw(tkey4,
-								    CKM_CONCATENATE_BASE_AND_DATA,
-								    vpss.spii,
-								    CKM_CONCATENATE_BASE_AND_DATA,
-								    CKA_DERIVE,
-								    0);
-			passert(tkey5 != NULL);
-
-			PK11SymKey *tkey6 = pk11_derive_wrapper_lsw(tkey5,
-								    CKM_CONCATENATE_BASE_AND_DATA,
-								    vpss.spir,
-								    CKM_CONCATENATE_BASE_AND_DATA,
-								    CKA_DERIVE,
-								    0);
-			passert(tkey6 != NULL);
-
-			chunk_t counter;
-
-			setchunk(counter, &vpss.counter[0], sizeof(vpss.counter[0]));
-			PK11SymKey *tkey7 = pk11_derive_wrapper_lsw(tkey6,
-								    CKM_CONCATENATE_BASE_AND_DATA,
-								    counter,
-								    nss_key_derivation_mech(prf_hasher),
-								    CKA_DERIVE,
-								    0);
-			passert(tkey7 != NULL);
-
-			PK11SymKey *tkey8 = PK11_Derive_lsw(tkey7,
-							    nss_key_derivation_mech(prf_hasher),
-							    NULL,
-							    CKM_CONCATENATE_BASE_AND_DATA,
-							    CKA_DERIVE,
-							    0);
-			passert(tkey8 != NULL);
-
-			PK11SymKey *tkey9 = pk11_derive_wrapper_lsw(tkey1,
-								    CKM_XOR_BASE_AND_DATA,
-								    hmac_opad,
-								    CKM_CONCATENATE_BASE_AND_KEY,
-								    CKA_DERIVE,
-								    0);
-			passert(tkey9 != NULL);
-
-			keyhandle = PK11_GetSymKeyHandle(tkey8);
-			param.data = (unsigned char*)&keyhandle;
-			param.len = sizeof(keyhandle);
-
-			PK11SymKey *tkey10 = PK11_Derive_lsw(tkey9,
-							     CKM_CONCATENATE_BASE_AND_KEY,
-							     &param,
-							     nss_key_derivation_mech(prf_hasher),
-							     CKA_DERIVE,
-							     0);
-			passert(tkey10 != NULL);
-
-			if (vpss.counter[0] == 0x01) {
-				finalkey = PK11_Derive_lsw(tkey10,
-							   nss_key_derivation_mech(prf_hasher),
-							   NULL,
-							   CKM_CONCATENATE_BASE_AND_KEY,
-							   CKA_DERIVE,
-							   0);
-				passert(finalkey != NULL);
-
-				tkey11 = PK11_Derive_lsw(tkey10,
-							 nss_key_derivation_mech(prf_hasher),
-							 NULL,
-							 CKM_CONCATENATE_BASE_AND_KEY,
-							 CKA_DERIVE,
-							 0);
-				passert(tkey11 != NULL);
-			} else {
-				tkey11 = PK11_Derive_lsw(tkey10,
-							 nss_key_derivation_mech(prf_hasher),
-							 NULL,
-							 CKM_EXTRACT_KEY_FROM_KEY,
-							 CKA_DERIVE,
-							 0);
-				passert(tkey11 != NULL);
-
-				keyhandle = PK11_GetSymKeyHandle(tkey11);
-				param.data = (unsigned char*)&keyhandle;
-				param.len = sizeof(keyhandle);
-
-				if ( total_keysize <=
-				     (PK11_GetKeyLength(finalkey) +
-				      PK11_GetKeyLength(tkey11)) ) {
-					finalkey = PK11_Derive_lsw(finalkey,
-								   CKM_CONCATENATE_BASE_AND_KEY,
-								   &param,
-								   CKM_EXTRACT_KEY_FROM_KEY,
-								   CKA_DERIVE,
-								   0);
-					passert(finalkey != NULL);
-				} else {
-					finalkey = PK11_Derive_lsw(finalkey,
-								   CKM_CONCATENATE_BASE_AND_KEY,
-								   &param,
-								   CKM_CONCATENATE_BASE_AND_KEY,
-								   CKA_DERIVE,
-								   0);
-					passert(finalkey != NULL);
-				}
-			}
-
-			PK11_FreeSymKey(tkey3);
-			PK11_FreeSymKey(tkey4);
-			PK11_FreeSymKey(tkey5);
-			PK11_FreeSymKey(tkey6);
-			PK11_FreeSymKey(tkey7);
-			PK11_FreeSymKey(tkey8);
-			PK11_FreeSymKey(tkey9);
-			PK11_FreeSymKey(tkey10);
-
-			if (total_keysize <= PK11_GetKeyLength(finalkey)) {
-				PK11_FreeSymKey(tkey1);
-				PK11_FreeSymKey(tkey11);
-				break;
-			}
-
-			vpss.counter[0]++;
-		}
-
-		DBG(DBG_CRYPT,
-		    DBG_log("NSS ikev2: finished computing key material for IKEv2 SA"));
-
-		CK_EXTRACT_PARAMS bs = 0;
-		size_t next_bit = 0;
-
-		SK_d_k = pk11_extract_derive_wrapper_lsw(finalkey, next_bit,
-							 CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-							 skd_bytes);
-		next_bit += skd_bytes * BITS_PER_BYTE;
-
-		SK_ai_k = pk11_extract_derive_wrapper_lsw(finalkey, next_bit,
-							  CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-							  integ_size);
-		next_bit += integ_size * BITS_PER_BYTE;
-
-		SK_ar_k = pk11_extract_derive_wrapper_lsw(finalkey, next_bit,
-							  CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-							  integ_size);
-		next_bit += integ_size * BITS_PER_BYTE;
-
-		bs = next_bit;
-		param1.data = (unsigned char*)&bs;
-		param1.len = sizeof(bs);
-		SK_ei_k = PK11_DeriveWithFlags(finalkey,
-					       CKM_EXTRACT_KEY_FROM_KEY,
-					       &param1,
-					       nss_encryption_mech(encrypter),
-					       CKA_FLAGS_ONLY, key_size,
-					       CKF_ENCRYPT | CKF_DECRYPT);
-		next_bit += key_size * BITS_PER_BYTE;
-
-		initiator_salt = chunk_from_symkey("initiator salt", finalkey,
-						   next_bit, salt_size);
-		next_bit += salt_size * BITS_PER_BYTE;
-
-		bs = next_bit;
-		param1.data = (unsigned char*)&bs;
-		param1.len = sizeof(bs);
-		SK_er_k = PK11_DeriveWithFlags(finalkey,
-					       CKM_EXTRACT_KEY_FROM_KEY,
-					       &param1,
-					       nss_encryption_mech(encrypter),
-					       CKA_FLAGS_ONLY, key_size,
-					       CKF_ENCRYPT | CKF_DECRYPT);
-		next_bit += key_size * BITS_PER_BYTE;
-
-		responder_salt = chunk_from_symkey("responder salt", finalkey,
-						   next_bit, salt_size);
-		next_bit += salt_size * BITS_PER_BYTE;
-
-		SK_pi_k = pk11_extract_derive_wrapper_lsw(finalkey, next_bit,
-							  CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-							  skp_bytes);
-		next_bit += skp_bytes * BITS_PER_BYTE;
-
-		SK_pr_k = pk11_extract_derive_wrapper_lsw(finalkey, next_bit,
-							  CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE,
-							  skp_bytes);
-		next_bit += skp_bytes * BITS_PER_BYTE;
-
-		DBG(DBG_CRYPT,
-		    DBG_log("NSS ikev2: finished computing individual keys for IKEv2 SA"));
-		PK11_FreeSymKey(finalkey);
-
-		*skeyseed_out = skeyseed_k;
-		*SK_d_out = SK_d_k;
-		*SK_ai_out = SK_ai_k;
-		*SK_ar_out = SK_ar_k;
-		*SK_ei_out = SK_ei_k;
-		*SK_er_out = SK_er_k;
-		*SK_pi_out = SK_pi_k;
-		*SK_pr_out = SK_pr_k;
-		*initiator_salt_out = initiator_salt;
-		*responder_salt_out = responder_salt;
-
-		freeanychunk(hmac_opad);
-		freeanychunk(hmac_ipad);
-		freeanychunk(hmac_pad_prf);
-	}
-	DBG(DBG_CRYPT,
-	    DBG_log("calc_skeyseed_v2 pointers: shared %p, skeyseed %p, SK_d %p, SK_ai %p, SK_ar %p, SK_ei %p, SK_er %p, SK_pi %p, SK_pr %p",
-		    shared, skeyseed_k, SK_d_k, SK_ai_k, SK_ar_k, SK_ei_k, SK_er_k, SK_pi_k, SK_pr_k);
-	    DBG_dump_chunk("calc_skeyseed_v2 initiator salt", initiator_salt);
-	    DBG_dump_chunk("calc_skeyseed_v2 responder salt", responder_salt));
-}
-
-/* MUST BE THREAD-SAFE */
-void calc_dh_v2(struct pluto_crypto_req *r)
-{
-	struct pcr_skeycalc_v2_r *skr = &r->pcr_d.dhv2;
-	struct pcr_skeyid_q dhq;
-	const struct oakley_group_desc *group;
-	PK11SymKey *shared;
-	chunk_t g;
-	SECKEYPrivateKey *ltsecret;
-	PK11SymKey *skeyseed;
-	PK11SymKey
-		*SK_d,
-		*SK_ai,
-		*SK_ar,
-		*SK_ei,
-		*SK_er,
-		*SK_pi,
-		*SK_pr;
-	chunk_t initiator_salt;
-	chunk_t responder_salt;
-	SECKEYPublicKey *pubk;
-
-	/* copy the request, since the reply will re-use the memory of the r->pcr_d.dhq */
-	memcpy(&dhq, &r->pcr_d.dhq, sizeof(r->pcr_d.dhq));
-
-	/* clear out the reply */
-	zero(skr);
-	INIT_WIRE_ARENA(*skr);
-
-	group = lookup_group(dhq.oakley_group);
-	passert(group != NULL);
-
-	ltsecret = dhq.secret;
-	pubk = dhq.pubk;
-
-	/* now calculate the (g^x)(g^y) --- need gi on responder, gr on initiator */
-
-	setchunk_from_wire(g, &dhq, dhq.role == O_RESPONDER ? &dhq.gi : &dhq.gr);
-
-	DBG(DBG_CRYPT, DBG_dump_chunk("peer's g: ", g));
-
-	shared = calc_dh_shared(g, ltsecret, group, pubk);
-
-	/* okay, so now all the shared key material */
-	calc_skeyseed_v2(&dhq,	/* input */
-			 shared,	/* input */
-			 dhq.key_size,	/* input */
-			 dhq.salt_size, /* input */
-
-			 &skeyseed,	/* output */
-			 &SK_d,	/* output */
-			 &SK_ai,	/* output */
-			 &SK_ar,	/* output */
-			 &SK_ei,	/* output */
-			 &SK_er,	/* output */
-			 &SK_pi,	/* output */
-			 &SK_pr,	/* output */
-			 &initiator_salt, /* output */
-			 &responder_salt); /* output */
-
-	skr->shared = shared;
-	skr->skeyseed = skeyseed;
-	skr->skeyid_d = SK_d;
-	skr->skeyid_ai = SK_ai;
-	skr->skeyid_ar = SK_ar;
-	skr->skeyid_ei = SK_ei;
-	skr->skeyid_er = SK_er;
-	skr->skeyid_pi = SK_pi;
-	skr->skeyid_pr = SK_pr;
-	skr->skey_initiator_salt = initiator_salt;
-	skr->skey_responder_salt = responder_salt;
-}
diff -Naur libreswan-3.12-orig/programs/pluto/crypt_dh.h libreswan-3.12/programs/pluto/crypt_dh.h
--- libreswan-3.12-orig/programs/pluto/crypt_dh.h	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/crypt_dh.h	2015-05-06 11:45:32.918301394 -0400
@@ -0,0 +1,46 @@
+/*
+ * DH crypto functions, for libreswan
+ *
+ * Copyright (C) 2007-2008 Michael C. Richardson <mcr@xelerance.com>
+ * Copyright (C) 2008 Antony Antony <antony@xelerance.com>
+ * Copyright (C) 2009 David McCullough <david_mccullough@securecomputing.com>
+ * Copyright (C) 2009-2012 Avesh Agarwal <avagarwa@redhat.com>
+ * Copyright (C) 2009-2010 Paul Wouters <paul@xelerance.com>
+ * Copyright (C) 2010 Tuomo Soini <tis@foobar.fi>
+ * Copyright (C) 2012-2013 Paul Wouters <paul@libreswan.org>
+ * Copyright (C) 2012 Wes Hardaker <opensource@hardakers.net>
+ * Copyright (C) 2013 Antony Antony <antony@phenome.org>
+ * Copyright (C) 2013 D. Hugh Redelmeier <hugh@mimosa.com>
+ * Copyright (C) 2015 Paul Wouters <pwouters@redhat.com>
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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 crypt_dh_h
+#define crypt_dh_h
+
+#include <pk11pub.h>
+#include "lswalloc.h"
+
+struct oakley_group_desc;
+
+PK11SymKey *calc_dh_shared(chunk_t g,	/* converted to SECItem */
+			   /*const*/ SECKEYPrivateKey *privk,	/* NSS doesn't do const */
+			   const struct oakley_group_desc *group,
+			   const SECKEYPublicKey *local_pubk);
+
+
+struct pluto_crypto_req;
+
+void calc_dh(struct pluto_crypto_req *r);
+
+#endif
diff -Naur libreswan-3.12-orig/programs/pluto/crypto.h libreswan-3.12/programs/pluto/crypto.h
--- libreswan-3.12-orig/programs/pluto/crypto.h	2014-11-06 22:52:50.000000000 -0500
+++ libreswan-3.12/programs/pluto/crypto.h	2015-05-06 11:45:32.918301394 -0400
@@ -127,24 +127,14 @@
 	aes_xcbc_context ctx_aes_xcbc;
 };
 
-/* HMAC package
- * Note that hmac_ctx can be (and is) copied since there are
- * no persistent pointers into it.
+/*
+ * HMAC package (new code should use crypt_prf).
  */
 
+struct crypt_prf;
 struct hmac_ctx {
-	const struct hash_desc *h;      /* underlying hash function */
-	size_t hmac_digest_len;         /* copy of h->hash_digest_len */
-	union hash_ctx hash_ctx;        /* ctx for hash function */
-	u_char buf1[HMAC_BUFSIZE], buf2[HMAC_BUFSIZE];
-#ifdef USE_SHA2
-	sha256_context ctx_sha256;
-	sha512_context ctx_sha512;
-#endif
-	aes_xcbc_context ctx_aes_xcbc;
-
-	PK11SymKey *ikey, *okey;
-	PK11Context *ctx_nss;
+	struct crypt_prf *prf;
+	size_t hmac_digest_len;
 };
 
 extern void hmac_init(struct hmac_ctx *ctx,
@@ -167,18 +157,7 @@
 }
 
 extern CK_MECHANISM_TYPE nss_key_derivation_mech(const struct hash_desc *hasher);
-extern void nss_symkey_log(PK11SymKey *key, const char *msg);
 extern chunk_t hmac_pads(u_char val, unsigned int len);
-extern PK11SymKey *pk11_derive_wrapper_lsw(PK11SymKey *base,
-					   CK_MECHANISM_TYPE mechanism,
-					   chunk_t data,
-					   CK_MECHANISM_TYPE target,
-					   CK_ATTRIBUTE_TYPE operation,
-					   int keySize);
-extern PK11SymKey *PK11_Derive_lsw(PK11SymKey *base,
-				   CK_MECHANISM_TYPE mechanism,
-				   SECItem *param, CK_MECHANISM_TYPE target,
-				   CK_ATTRIBUTE_TYPE operation, int keySize);
 
 enum crk_proto {
 	CRK_ESPorAH,
diff -Naur libreswan-3.12-orig/programs/pluto/crypt_prf.c libreswan-3.12/programs/pluto/crypt_prf.c
--- libreswan-3.12-orig/programs/pluto/crypt_prf.c	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/crypt_prf.c	2015-05-06 11:45:32.919301405 -0400
@@ -0,0 +1,203 @@
+/*
+ * PRF helper functions, for libreswan
+ *
+ * Copyright (C) 2007-2008 Michael C. Richardson <mcr@xelerance.com>
+ * Copyright (C) 2008 Antony Antony <antony@xelerance.com>
+ * Copyright (C) 2009 David McCullough <david_mccullough@securecomputing.com>
+ * Copyright (C) 2009-2012 Avesh Agarwal <avagarwa@redhat.com>
+ * Copyright (C) 2009-2010 Paul Wouters <paul@xelerance.com>
+ * Copyright (C) 2010 Tuomo Soini <tis@foobar.fi>
+ * Copyright (C) 2012-2013 Paul Wouters <paul@libreswan.org>
+ * Copyright (C) 2012 Wes Hardaker <opensource@hardakers.net>
+ * Copyright (C) 2013 Antony Antony <antony@phenome.org>
+ * Copyright (C) 2013 D. Hugh Redelmeier <hugh@mimosa.com>
+ * Copyright (C) 2015 Paul Wouters <pwouters@redhat.com>
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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 <stdlib.h>
+
+//#include "libreswan.h"
+#include "lswalloc.h"
+#include "lswlog.h"
+#include "ike_alg.h"
+#include "crypt_prf.h"
+#include "crypt_symkey.h"
+#include "crypto.h"
+
+struct crypt_prf {
+	const char *name;
+	const struct hash_desc *hasher;
+	/* for converting chunks to symkeys */
+	PK11SymKey *scratch;
+	/* Did we allocate KEY? */
+	bool we_own_key;
+	/* intermediate values */
+	PK11SymKey *key;
+	PK11SymKey *inner;
+};
+
+/*
+ * During the init phase, accumulate the key material in KEY.
+ */
+struct crypt_prf *crypt_prf_init(const char *name, const struct hash_desc *hasher,
+				 PK11SymKey *scratch)
+{
+	struct crypt_prf *prf = alloc_bytes(sizeof(struct crypt_prf), name);
+	DBG(DBG_CRYPT, DBG_log("%s prf: init %p", name, prf));
+	prf->name = name;
+	prf->hasher = hasher;
+	prf->scratch = scratch;
+	prf->we_own_key = FALSE;
+	prf->key = NULL;
+	prf->inner = NULL;
+	return prf;
+}
+
+/*
+ * Update KEY marking it as ours.  Only call with a KEY we created.
+ */
+static void update_key(struct crypt_prf *prf, PK11SymKey *key)
+{
+	if (prf->we_own_key) {
+		free_any_symkey(__func__, &prf->key);
+	}
+	prf->we_own_key = TRUE;
+	prf->key = key;
+}
+
+void crypt_prf_init_symkey(const char *name, struct crypt_prf *prf, PK11SymKey *key)
+{
+	DBG(DBG_CRYPT, DBG_log("%s prf: init symkey %s %p (length %d)",
+			       prf->name, name, key, PK11_GetKeyLength(key)));
+	if (prf->key == NULL) {
+		prf->we_own_key = FALSE;
+		prf->key = key;
+	} else {
+		update_key(prf, concat_symkey_symkey(prf->hasher, prf->key, key));
+	}
+}
+
+void crypt_prf_init_chunk(const char *name, struct crypt_prf *prf, chunk_t key)
+{
+	DBG(DBG_CRYPT, DBG_log("%s prf: init chunk %s %p (length %zd)",
+			       prf->name, name, key.ptr, key.len));
+	if (prf->key == NULL) {
+		prf->key = symkey_from_chunk(prf->scratch, key);
+		prf->we_own_key = TRUE;
+	} else {
+		update_key(prf, concat_symkey_chunk(prf->hasher, prf->key, key));
+	}
+}
+
+/*
+ * Prepare for update phase (accumulate seed material).
+ */
+void crypt_prf_update(struct crypt_prf *prf)
+{
+	DBG(DBG_CRYPT, DBG_log("%s prf: update", prf->name));
+	/* create the prf key from KEY.  */
+	passert(prf->key != NULL);
+	/* If the key is too big, re-hash it down to size. */
+	if (PK11_GetKeyLength(prf->key) > prf->hasher->hash_block_size) {
+		update_key(prf, hash_symkey(prf->hasher, prf->key));
+	}
+	/* If the key is too small, pad it. */
+	if (PK11_GetKeyLength(prf->key) < prf->hasher->hash_block_size) {
+		/* pad it to block_size. */
+		chunk_t hmac_pad_prf = hmac_pads(0x00,
+						 (prf->hasher->hash_block_size -
+						  PK11_GetKeyLength(prf->key)));
+		update_key(prf, concat_symkey_chunk(prf->hasher, prf->key,
+						    hmac_pad_prf));
+		freeanychunk(hmac_pad_prf);
+	}
+	passert(prf->key != NULL);
+
+	/* Start forming the inner hash input: (key^IPAD)|... */
+	passert(prf->inner == NULL);
+	chunk_t hmac_ipad = hmac_pads(HMAC_IPAD, prf->hasher->hash_block_size);
+	prf->inner = xor_symkey_chunk(prf->key, hmac_ipad);
+	freeanychunk(hmac_ipad);
+}
+
+void crypt_prf_update_chunk(const char *name, struct crypt_prf *prf,
+			    chunk_t update)
+{
+	DBG(DBG_CRYPT, DBG_log("%s prf: update chunk %s %p (length %zd)",
+			       prf->name, name, update.ptr, update.len));
+	append_symkey_chunk(prf->hasher, &(prf->inner), update);
+}
+
+void crypt_prf_update_symkey(const char *name, struct crypt_prf *prf,
+			     PK11SymKey *update)
+{
+	DBG(DBG_CRYPT, DBG_log("%s prf: update symkey %s %p (length %d)",
+			       prf->name, name, update,
+			       PK11_GetKeyLength(update)));
+	append_symkey_symkey(prf->hasher, &(prf->inner), update);
+}
+
+void crypt_prf_update_byte(const char *name, struct crypt_prf *prf,
+			   uint8_t update)
+{
+	DBG(DBG_CRYPT, DBG_log("%s prf: update byte %s", prf->name, name));
+	append_symkey_byte(prf->hasher, &(prf->inner), update);
+}
+
+void crypt_prf_update_bytes(const char *name, struct crypt_prf *prf,
+			    const void *update, size_t sizeof_update)
+{
+	DBG(DBG_CRYPT, DBG_log("%s prf: update bytes %s %p (length %zd)",
+			       prf->name, name, update, sizeof_update));
+	append_symkey_bytes(prf->hasher, &(prf->inner), update, sizeof_update);
+}
+
+PK11SymKey *crypt_prf_final(struct crypt_prf *prf)
+{
+	DBG(DBG_CRYPT, DBG_log("%s prf: final", prf->name));
+	passert(prf->inner != NULL);
+	/* run that through hasher */
+	PK11SymKey *hashed_inner = hash_symkey(prf->hasher, prf->inner);
+	free_any_symkey("prf inner", &prf->inner);
+
+	/* Input to outer hash: (key^OPAD)|hashed_inner.  */
+	chunk_t hmac_opad = hmac_pads(HMAC_OPAD, prf->hasher->hash_block_size);
+	PK11SymKey *outer = xor_symkey_chunk(prf->key, hmac_opad);
+	freeanychunk(hmac_opad);
+	append_symkey_symkey(prf->hasher, &outer, hashed_inner);
+	free_any_symkey("prf hashed inner", &hashed_inner);
+
+	/* Finally hash that */
+	PK11SymKey *hashed_outer = hash_symkey(prf->hasher, outer);
+	free_any_symkey("prf outer", &outer);
+
+	if (prf->we_own_key) {
+		free_any_symkey("prf key", &prf->key);
+	}
+	prf->key = NULL; /* help debug */
+	pfree(prf);
+
+	DBG(DBG_CRYPT, DBG_dump_symkey("prf result", hashed_outer));
+	return hashed_outer;
+}
+
+void crypt_prf_final_bytes(struct crypt_prf *prf,
+			   void *bytes, size_t sizeof_bytes)
+{
+	const char *name = prf->name;
+	PK11SymKey *result = crypt_prf_final(prf);
+	prf = NULL; /* no longer valid */
+	bytes_from_symkey_bytes(name, result, 0, bytes, sizeof_bytes);
+	free_any_symkey(__func__, &result);
+}
diff -Naur libreswan-3.12-orig/programs/pluto/crypt_prf.h libreswan-3.12/programs/pluto/crypt_prf.h
--- libreswan-3.12-orig/programs/pluto/crypt_prf.h	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/crypt_prf.h	2015-05-06 11:45:32.919301405 -0400
@@ -0,0 +1,86 @@
+/*
+ * prf and keying material helper functions, for libreswan
+ *
+ * Copyright (C) 2007 Michael C. Richardson <mcr@xelerance.com>
+ * Copyright (C) 2010 Paul Wouters <paul@xelerance.com>
+ * Copyright (C) 2013 D. Hugh Redelmeier <hugh@mimosa.com>
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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 crypt_prf_h
+#define crypt_prf_h
+
+#include <pk11pub.h>
+
+struct hash_desc;
+struct crypt_prf;
+
+/*
+ * Primitives implementing PRF described in rfc2104.
+ *
+ * This implementation tries to keep all the input and output material
+ * secure inside SymKeys.  To that end, it should be good for
+ * generating keying material.
+ *
+ * The slightly clunky, interface is described in-line below.
+ */
+
+/*
+ * Call this first; always.
+ *
+ * SCRATCH is used as a secure starting point when the key is formed
+ * from raw bytes (or memory).
+ */
+struct crypt_prf *crypt_prf_init(const char *name,
+				 const struct hash_desc *hasher,
+				 PK11SymKey *scratch);
+
+/*
+ * Next load up the raw-key by calling one or more of the following.
+ * Multiple calls concatenate the key.
+ *
+ * Even when SCRATCH above was passed the KEY, the below must be
+ * called.
+ */
+void crypt_prf_init_symkey(const char *name, struct crypt_prf *prf, PK11SymKey *key);
+void crypt_prf_init_chunk(const char *name, struct crypt_prf *prf,
+			  chunk_t key);
+void crypt_prf_init_bytes(const char *name, struct crypt_prf *prf,
+			  const void *key, size_t sizeof_key);
+
+/*
+ * Then call this to flip to seed/data/text mode; always.
+ */
+void crypt_prf_update(struct crypt_prf *prf);
+
+/*
+ * Call these to accumulate the seed/data/text.
+ */
+void crypt_prf_update_chunk(const char *name, struct crypt_prf *prf,
+			    chunk_t update);
+void crypt_prf_update_symkey(const char *name, struct crypt_prf *prf,
+			     PK11SymKey *update);
+void crypt_prf_update_byte(const char *name, struct crypt_prf *prf, uint8_t byte);
+void crypt_prf_update_bytes(const char *name, struct crypt_prf *prf,
+			    const void *bytes, size_t count);
+
+/*
+ * Finally ...
+ *
+ * This will free PRF.
+ */
+PK11SymKey *crypt_prf_final(struct crypt_prf *prf);
+void crypt_prf_final_bytes(struct crypt_prf *prf,
+			   void *bytes, size_t sizeof_bytes);
+
+#endif
diff -Naur libreswan-3.12-orig/programs/pluto/crypt_symkey.c libreswan-3.12/programs/pluto/crypt_symkey.c
--- libreswan-3.12-orig/programs/pluto/crypt_symkey.c	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/crypt_symkey.c	2015-05-06 11:45:32.920301417 -0400
@@ -0,0 +1,468 @@
+/*
+ * SYMKEY manipulation functions, for libreswan
+ *
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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 "libreswan.h"
+#include "lswalloc.h"
+#include "lswlog.h"
+#include "ike_alg.h"
+#include "crypt_symkey.h"
+#include "crypto.h"
+
+/*
+ * XXX: Is there an NSS version of this?
+ */
+
+static const char *ckm_to_string(CK_MECHANISM_TYPE mechanism)
+{
+	const char *t;
+#define CASE(T) case T: t = #T; eat(t, "CKM_"); return t
+	switch (mechanism) {
+
+		CASE(CKM_CONCATENATE_BASE_AND_DATA);
+		CASE(CKM_CONCATENATE_BASE_AND_KEY);
+		CASE(CKM_CONCATENATE_DATA_AND_BASE);
+
+		CASE(CKM_XOR_BASE_AND_DATA);
+
+		CASE(CKM_EXTRACT_KEY_FROM_KEY);
+
+		CASE(CKM_VENDOR_DEFINED);
+
+		CASE(CKM_AES_CBC);
+		CASE(CKM_DES3_CBC);
+		CASE(CKM_CAMELLIA_CBC);
+		CASE(CKM_AES_CTR);
+		CASE(CKM_AES_GCM);
+
+		CASE(CKM_MD5_KEY_DERIVATION);
+		CASE(CKM_SHA1_KEY_DERIVATION);
+		CASE(CKM_SHA256_KEY_DERIVATION);
+		CASE(CKM_SHA384_KEY_DERIVATION);
+		CASE(CKM_SHA512_KEY_DERIVATION);
+
+	default:
+		DBG(DBG_CRYPT, DBG_log("unknown mechanism 0x%08x", (int) mechanism));
+		return "unknown-mechanism";
+	}
+#undef CASE
+}
+
+void free_any_symkey(const char *prefix, PK11SymKey **key)
+{
+	if (*key != NULL) {
+		DBG(DBG_CRYPT, DBG_log("%s: free key %p", prefix, *key));
+		PK11_FreeSymKey(*key);
+	} else {
+		DBG(DBG_CRYPT, DBG_log("%s: free key NULL", prefix));
+	}
+	*key = NULL;
+}
+
+void DBG_dump_symkey(const char *prefix, PK11SymKey *key)
+{
+	if (key == NULL) {
+		/*
+		 * For instance, when a zero-length key gets extracted
+		 * from an existing key.
+		 */
+		DBG_log("%s key is NULL", prefix);
+	} else {
+		DBG_log("%s key %p %d mechanism(type) %s",
+			prefix, key, PK11_GetKeyLength(key),
+			ckm_to_string(PK11_GetMechanism(key)));
+		if (DBGP(DBG_PRIVATE)) {
+			chunk_t chunk = chunk_from_symkey(prefix, key);
+			DBG_dump_chunk(prefix, chunk);
+			freeanychunk(chunk);
+		} else {
+			DBG_log("%s contents are private", prefix);
+		}
+	}
+}
+
+/*
+ * XXX: Is there any documentation on this generic operation?
+ */
+static PK11SymKey *merge_symkey_bytes(PK11SymKey *base_key,
+				      const void *bytes, size_t sizeof_bytes,
+				      CK_MECHANISM_TYPE derive,
+				      CK_MECHANISM_TYPE target)
+{
+	passert(sizeof_bytes > 0);
+	CK_KEY_DERIVATION_STRING_DATA string = {
+		.pData = (void *)bytes,
+		.ulLen = sizeof_bytes,
+	};
+	SECItem param = {
+		.data = (unsigned char*)&string,
+		.len = sizeof(string),
+	};
+	CK_ATTRIBUTE_TYPE operation = CKA_DERIVE;
+	int key_size = 0;
+
+	DBG(DBG_CRYPT,
+	    DBG_log("derive %s using %s", ckm_to_string(derive),
+		    ckm_to_string(target));
+	    DBG_dump_symkey("base", base_key);
+	    DBG_dump("data", bytes, sizeof_bytes));
+	PK11SymKey *result = PK11_Derive(base_key, derive, &param, target,
+					 operation, key_size);
+	DBG(DBG_CRYPT, DBG_dump_symkey("result", result));
+
+	return result;
+}
+
+/*
+ * SYMKEY I/O operations.
+ *
+ * SYMKEY_FROM_CHUNK uses the SCRATCH key as a secure starting point
+ * for creating the key.
+ */
+
+PK11SymKey *symkey_from_bytes(PK11SymKey *scratch, const void *bytes,
+			      size_t sizeof_bytes)
+{
+	PK11SymKey *tmp = merge_symkey_bytes(scratch, bytes, sizeof_bytes,
+					     CKM_CONCATENATE_DATA_AND_BASE,
+					     CKM_EXTRACT_KEY_FROM_KEY);
+	passert(tmp != NULL);
+	PK11SymKey *key = key_from_symkey_bytes(tmp, 0, sizeof_bytes);
+	passert(key != NULL);
+	free_any_symkey(__func__, &tmp);
+	return key;
+}
+
+PK11SymKey *symkey_from_chunk(PK11SymKey *scratch, chunk_t chunk)
+{
+	return symkey_from_bytes(scratch, chunk.ptr, chunk.len);
+}
+
+/*
+ * Concatenate two pieces of keying material creating a
+ * new SYMKEY object.
+ */
+
+PK11SymKey *concat_symkey_symkey(const struct hash_desc *hasher,
+				 PK11SymKey *lhs, PK11SymKey *rhs)
+{
+	CK_OBJECT_HANDLE keyhandle = PK11_GetSymKeyHandle(rhs);
+	/* give the parameters explicit names - there are too many */
+	PK11SymKey *base_key = lhs;
+	CK_MECHANISM_TYPE derive = CKM_CONCATENATE_BASE_AND_KEY;
+	SECItem param = {
+		.data = (unsigned char*)&keyhandle,
+		.len = sizeof(keyhandle)
+	};
+	CK_MECHANISM_TYPE target = nss_key_derivation_mech(hasher);
+	CK_ATTRIBUTE_TYPE operation = CKA_DERIVE;
+	int key_size = 0;
+
+	DBG(DBG_CRYPT,
+	    DBG_log("concate symkey(base) symkey(key) target %s",
+		    ckm_to_string(target));
+	    DBG_dump_symkey("base", lhs);
+	    DBG_dump_symkey("key", rhs));
+	PK11SymKey *result = PK11_Derive(base_key, derive, &param, target,
+					 operation, key_size);
+	DBG(DBG_CRYPT, DBG_dump_symkey("result", result));
+
+	return result;
+}
+
+PK11SymKey *concat_symkey_bytes(const struct hash_desc *hasher,
+				PK11SymKey *lhs, const void *rhs,
+				size_t sizeof_rhs)
+{
+	CK_MECHANISM_TYPE mechanism = nss_key_derivation_mech(hasher);
+	return merge_symkey_bytes(lhs, rhs, sizeof_rhs,
+				  CKM_CONCATENATE_BASE_AND_DATA,
+				  mechanism);
+}
+
+PK11SymKey *concat_symkey_chunk(const struct hash_desc *hasher,
+				PK11SymKey *lhs, chunk_t rhs)
+{
+	return concat_symkey_bytes(hasher, lhs, rhs.ptr, rhs.len);
+}
+
+PK11SymKey *concat_symkey_byte(const struct hash_desc *hasher,
+			       PK11SymKey *lhs, uint8_t rhs)
+{
+	return concat_symkey_bytes(hasher, lhs, &rhs, sizeof(rhs));
+}
+
+/*
+ * Append new keying material to an existing key; replace the existing
+ * key with the result.
+ *
+ * Use this to chain a series of concat operations.
+ */
+
+void append_symkey_symkey(const struct hash_desc *hasher,
+			  PK11SymKey **lhs, PK11SymKey *rhs)
+{
+	PK11SymKey *newkey = concat_symkey_symkey(hasher, *lhs, rhs);
+	free_any_symkey(__func__, lhs);
+	*lhs = newkey;
+}
+
+void append_symkey_bytes(const struct hash_desc *hasher,
+			 PK11SymKey **lhs, const void *rhs,
+			 size_t sizeof_rhs)
+{
+	PK11SymKey *newkey = concat_symkey_bytes(hasher, *lhs,
+						 rhs, sizeof_rhs);
+	free_any_symkey(__func__, lhs);
+	*lhs = newkey;
+}
+
+void append_symkey_chunk(const struct hash_desc *hasher,
+			 PK11SymKey **lhs, chunk_t rhs)
+{
+	append_symkey_bytes(hasher, lhs, rhs.ptr, rhs.len);
+}
+
+void append_symkey_byte(const struct hash_desc *hasher,
+			PK11SymKey **lhs, uint8_t rhs)
+{
+	append_symkey_bytes(hasher, lhs, &rhs, sizeof(rhs));
+}
+
+/*
+ * Extract raw-bytes from a SYMKEY.
+ *
+ * Offset into the SYMKEY is in either BITS or BYTES.
+ */
+
+static PK11SymKey *key_from_key_bits(PK11SymKey *base_key,
+				     CK_MECHANISM_TYPE target,
+				     CK_FLAGS flags,
+				     size_t next_bit, size_t key_size)
+{
+	/* spell out all the parameters */
+	CK_EXTRACT_PARAMS bs = next_bit;
+	SECItem param = {
+		.data = (unsigned char*)&bs,
+		.len = sizeof(bs),
+	};
+	CK_MECHANISM_TYPE derive = CKM_EXTRACT_KEY_FROM_KEY;
+	CK_ATTRIBUTE_TYPE operation = CKA_FLAGS_ONLY;
+
+	DBG(DBG_CRYPT,
+	    DBG_log("%s key from base key bits %zd length %zd flags 0x%lx",
+		    ckm_to_string(target), next_bit, key_size, flags);
+	    DBG_dump_symkey("base key", base_key));
+	PK11SymKey *result = PK11_DeriveWithFlags(base_key, derive, &param,
+						  target, operation,
+						  key_size, flags);
+	DBG(DBG_CRYPT, DBG_dump_symkey("result", result));
+
+	return result;
+}
+
+void *bytes_from_symkey_bits(const char *name,
+			     PK11SymKey *source_key, size_t next_bit,
+			     void *bytes, size_t sizeof_bytes)
+{
+	DBG(DBG_CRYPT,
+	    DBG_log("%s: extracting %zd bytes starting at bit %zd from symkey %p into %p",
+		    name, sizeof_bytes, next_bit, source_key, bytes));
+	if (sizeof_bytes == 0) {
+		return NULL;
+	}
+	PK11SymKey *sym_key = key_from_key_bits(source_key,
+						CKM_VENDOR_DEFINED, 0,
+						next_bit, sizeof_bytes);
+	if (sym_key == NULL) {
+		loglog(RC_LOG_SERIOUS, "NSS key-from-key failed while generating %s", name);
+		return NULL;
+	}
+	SECStatus s = PK11_ExtractKeyValue(sym_key);
+	if (s != SECSuccess) {
+		loglog(RC_LOG_SERIOUS, "NSS: PK11_ExtractKeyValue failed while generating %s", name);
+		return NULL;
+	}
+	/* Internal structure address, do not free.  */
+	SECItem *data = PK11_GetKeyData(sym_key);
+	if (data == NULL) {
+		loglog(RC_LOG_SERIOUS, "NSS: PK11_GetKeyData failed while generating %s", name);
+		return NULL;
+	}
+	DBG(DBG_CRYPT,
+	    DBG_log("chunk_from_symkey: %s: extracted len %d bytes at %p",
+		    name, data->len, data->data));
+	if (data->len != sizeof_bytes) {
+		loglog(RC_LOG_SERIOUS, "NSS: PK11_GetKeyData returned wrong number of bytes while generating %s", name);
+		return NULL;
+	}
+	/* Only alloc, when all looks good.  */
+	if (bytes == NULL) {
+		bytes = alloc_bytes(sizeof_bytes, name);
+		DBG(DBG_CRYPT,
+		    DBG_log("%s: allocated %zd bytes at %p",
+			    name, sizeof_bytes, bytes));
+	}
+	memcpy(bytes, data->data, sizeof_bytes);
+	DBG(DBG_PRIVATE, DBG_dump(name, bytes, sizeof_bytes));
+	free_any_symkey(__func__, &sym_key);
+	
+	return bytes;
+}
+
+void *bytes_from_symkey_bytes(const char *name, PK11SymKey *source_key,
+			      size_t next_byte, void *bytes,
+			      size_t sizeof_bytes)
+{
+	return bytes_from_symkey_bits(name, source_key,
+				      next_byte * BITS_PER_BYTE,
+				      bytes, sizeof_bytes);
+}
+
+chunk_t chunk_from_symkey_bits(const char *name, PK11SymKey *source_key,
+			       size_t next_bit, size_t sizeof_chunk)
+{
+	void *bytes = bytes_from_symkey_bits(name, source_key, next_bit,
+					     NULL, sizeof_chunk);
+	if (bytes == NULL) {
+		return empty_chunk;
+	}
+	chunk_t chunk;
+	setchunk(chunk, bytes, sizeof_chunk);
+	return chunk;
+}
+
+chunk_t chunk_from_symkey_bytes(const char *name, PK11SymKey *source_key,
+				size_t next_byte, size_t sizeof_chunk)
+{
+	return chunk_from_symkey_bits(name, source_key,
+				      next_byte * BITS_PER_BYTE, sizeof_chunk);
+}
+
+chunk_t chunk_from_symkey(const char *name, PK11SymKey *source_key)
+{
+	return chunk_from_symkey_bits(name, source_key, 0,
+				      PK11_GetKeyLength(source_key));
+}
+
+/*
+ * Extract SIZEOF_SYMKEY bytes of keying material as an ENCRYPTER key
+ * (i.e., can be used to encrypt/decrypt data using ENCRYPTER).
+ *
+ * Offset into the SYMKEY is in either BITS or BYTES.
+ */
+
+PK11SymKey *encrypt_key_from_symkey_bits(PK11SymKey *source_key,
+					 const struct encrypt_desc *encrypter,
+					 size_t next_bit, size_t sizeof_symkey)
+{
+	return key_from_key_bits(source_key,
+				 nss_encryption_mech(encrypter),
+				 CKF_ENCRYPT | CKF_DECRYPT,
+				 next_bit, sizeof_symkey);
+}
+
+PK11SymKey *encrypt_key_from_symkey_bytes(PK11SymKey *source_key,
+					  const struct encrypt_desc *encrypter,
+					  size_t next_byte, size_t sizeof_symkey)
+{
+	return encrypt_key_from_symkey_bits(source_key, encrypter,
+					    next_byte * BITS_PER_BYTE,
+					    sizeof_symkey);
+}
+
+/*
+ * Extract SIZEOF_KEY bytes of keying material as a KEY.  It inherits
+ * the BASE_KEYs type.  Good for hash keys.
+ *
+ * Offset into the SYMKEY is in either BITS or BYTES.
+ */
+
+PK11SymKey *key_from_symkey_bits(PK11SymKey *base_key,
+				 size_t next_bit, size_t key_size)
+{				    
+	CK_EXTRACT_PARAMS bs = next_bit;
+	SECItem param = {
+		.data = (unsigned char*)&bs,
+		.len = sizeof(bs),
+	};
+	CK_MECHANISM_TYPE derive = CKM_EXTRACT_KEY_FROM_KEY;
+	CK_MECHANISM_TYPE target = CKM_CONCATENATE_BASE_AND_DATA;
+	CK_ATTRIBUTE_TYPE operation = CKA_DERIVE;
+	/* XXX: can this use key_from_key_bits? */
+
+	DBG(DBG_CRYPT,
+	    DBG_log("%s key from symkey(base key) bits %zd length %zd",
+		    ckm_to_string(target),
+		     next_bit, key_size);
+	    DBG_dump_symkey("base key", base_key));
+	PK11SymKey *result = PK11_Derive(base_key, derive, &param, target,
+					 operation, key_size);
+	DBG(DBG_CRYPT, DBG_dump_symkey("result", result));
+
+	return result;
+}
+
+PK11SymKey *key_from_symkey_bytes(PK11SymKey *source_key,
+				  size_t next_byte, size_t sizeof_key)
+{
+	return key_from_symkey_bits(source_key,
+				    next_byte * BITS_PER_BYTE,
+				    sizeof_key);
+}
+
+/*
+ * Run HASHER on the key.
+ *
+ * This assumes that NSS works.  Based on old code, 3.14 may have had
+ * problems with SHA-2.
+ */
+PK11SymKey *hash_symkey(const struct hash_desc *hasher,
+			PK11SymKey *base_key)
+{
+	CK_MECHANISM_TYPE derive = nss_key_derivation_mech(hasher);
+	SECItem *param = NULL;
+	CK_MECHANISM_TYPE target = CKM_CONCATENATE_BASE_AND_KEY;
+	CK_ATTRIBUTE_TYPE operation = CKA_DERIVE;
+	int key_size = 0;
+
+	DBG(DBG_CRYPT,
+	    DBG_log("%s hash symkey(base key)", ckm_to_string(derive));
+	    DBG_dump_symkey("base key", base_key));
+	PK11SymKey *result = PK11_Derive(base_key, derive, param, target,
+					 operation, key_size);
+	DBG(DBG_CRYPT, DBG_dump_symkey("result", result));
+	
+	return result;
+}
+
+/*
+ * XOR a symkey with a chunk.
+ *
+ * XXX: hmac.c had very similar code, only, instead of
+ * target=CKM_CONCATENATE_BASE_AND_DATA it used
+ * target=hasher-to-ckm(hasher).
+ *
+ * hasher-to-ckm maped hasher->common.alg_id to CMK vis: OAKLEY_MD5 ->
+ * CKM_MD5; OAKLEY_SHA1 -> CKM_SHA_1; OAKLEY_SHA2_256 -> CKM_SHA256;
+ * OAKLEY_SHA2_384 -> CKM_SHA384; OAKLEY_SHA2_512 -> CKM_SHA512; only
+ * in the default case it would set target to 0x80000000????
+ */
+PK11SymKey *xor_symkey_chunk(PK11SymKey *lhs, chunk_t rhs)
+{
+	return merge_symkey_bytes(lhs, rhs.ptr, rhs.len,
+				  CKM_XOR_BASE_AND_DATA,
+				  CKM_CONCATENATE_BASE_AND_DATA);
+}
diff -Naur libreswan-3.12-orig/programs/pluto/crypt_symkey.h libreswan-3.12/programs/pluto/crypt_symkey.h
--- libreswan-3.12-orig/programs/pluto/crypt_symkey.h	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/crypt_symkey.h	2015-05-06 11:45:32.920301417 -0400
@@ -0,0 +1,131 @@
+/*
+ * SYMKEY manipulation functions, for libreswan
+ *
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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 crypt_symkey_h
+#define crypt_symkey_h
+
+#include <stdio.h>
+#include <pk11pub.h>
+#include "lswalloc.h"
+
+struct hash_desc;
+struct encrypt_desc;
+
+void DBG_dump_symkey(const char *prefix, PK11SymKey *key);
+
+/*
+ * Free any symkey and then stomp on the pointer.
+ */
+void free_any_symkey(const char *prefix, PK11SymKey **key);
+
+/*
+ * Use SCRATCH key as a secure starting point for creating the key
+ * from the raw bytes, or chunk.
+ */
+
+PK11SymKey *symkey_from_bytes(PK11SymKey *scratch, const void *bytes,
+			      size_t sizeof_bytes);
+  
+PK11SymKey *symkey_from_chunk(PK11SymKey *scratch, chunk_t chunk);
+
+/*
+ * Concatenate two pieces of keying material creating a
+ * new SYMKEY object.
+ */
+PK11SymKey *concat_symkey_symkey(const struct hash_desc *hasher,
+				 PK11SymKey *lhs, PK11SymKey *rhs);
+PK11SymKey *concat_symkey_bytes(const struct hash_desc *hasher,
+				PK11SymKey *lhs, const void *rhs,
+				size_t sizeof_rhs);
+PK11SymKey *concat_symkey_chunk(const struct hash_desc *hasher,
+				PK11SymKey *lhs, chunk_t rhs);
+PK11SymKey *concat_symkey_byte(const struct hash_desc *hasher,
+			       PK11SymKey *lhs, uint8_t rhs);
+
+/*
+ * Append new keying material to an existing key; replace the existing
+ * key with the result.
+ *
+ * Use this to chain a series of concat operations.
+ */
+void append_symkey_symkey(const struct hash_desc *hasher,
+			  PK11SymKey **lhs, PK11SymKey *rhs);
+void append_symkey_bytes(const struct hash_desc *hasher,
+			 PK11SymKey **lhs, const void *rhs,
+			 size_t sizeof_rhs);
+void append_symkey_chunk(const struct hash_desc *hasher,
+			 PK11SymKey **lhs, chunk_t rhs);
+void append_symkey_byte(const struct hash_desc *hasher,
+			PK11SymKey **lhs, uint8_t rhs);
+
+/*
+ * Extract raw-bytes from a SYMKEY.
+ *
+ * Offset into the SYMKEY is in either BITS or BYTES.
+ *
+ * bytes_from_ has a querk where, if BYTES is NULL, the buffer is
+ * allocated.
+ */
+void *bytes_from_symkey_bits(const char *name, PK11SymKey *source_key,
+			     size_t next_bit, void *bytes,
+			     size_t sizeof_bytes);
+void *bytes_from_symkey_bytes(const char *name, PK11SymKey *source_key,
+			      size_t next_byte, void *bytes,
+			      size_t sizeof_bytes);
+chunk_t chunk_from_symkey_bits(const char *name, PK11SymKey *source_key,
+			       size_t next_bit, size_t sizeof_chunk);
+chunk_t chunk_from_symkey_bytes(const char *name, PK11SymKey *source_key,
+				size_t next_byte, size_t sizeof_chunk);
+chunk_t chunk_from_symkey(const char *name, PK11SymKey *source_key);
+
+/*
+ * Extract SIZEOF_SYMKEY bytes of keying material as an ENCRYPTER key
+ * (i.e., can be used to encrypt/decrypt data using ENCRYPTER).
+ *
+ * Offset into the SYMKEY is in either BITS or BYTES.
+ */
+PK11SymKey *encrypt_key_from_symkey_bytes(PK11SymKey *source_key,
+					  const struct encrypt_desc *encrypter,
+					  size_t next_byte, size_t sizeof_symkey);
+PK11SymKey *encrypt_key_from_symkey_bits(PK11SymKey *source_key,
+					 const struct encrypt_desc *encrypter,
+					 size_t next_bit, size_t sizeof_symkey);
+
+/*
+ * Extract SIZEOF_KEY bytes of keying material as a KEY.  It inherits
+ * the BASE_KEYs type.  Good for hash keys.
+ *
+ * Offset into the SYMKEY is in either BITS or BYTES.
+ */
+PK11SymKey *key_from_symkey_bits(PK11SymKey *base_key,
+				 size_t next_bit, size_t key_size);
+PK11SymKey *key_from_symkey_bytes(PK11SymKey *source_key,
+				  size_t next_byte, size_t sizeof_key);
+
+/*
+ * Hash a symkey using HASHER.
+ *
+ * This gets used by the PRF when the BASE_KEY is too long.
+ */
+PK11SymKey *hash_symkey(const struct hash_desc *hasher,
+			PK11SymKey *base_key);
+
+/*
+ * XOR a symkey with a chunk.
+ */
+PK11SymKey *xor_symkey_chunk(PK11SymKey *lhs, chunk_t rhs);
+
+#endif
diff -Naur libreswan-3.12-orig/programs/pluto/ctr_test_vectors.c libreswan-3.12/programs/pluto/ctr_test_vectors.c
--- libreswan-3.12-orig/programs/pluto/ctr_test_vectors.c	2015-05-06 11:44:21.564466307 -0400
+++ libreswan-3.12/programs/pluto/ctr_test_vectors.c	2015-05-06 11:45:32.921301428 -0400
@@ -12,6 +12,7 @@
 
 #include "nss.h"
 #include "pk11pub.h"
+#include "crypt_symkey.h"
 
 struct ctr_test_vector {
 	// CK_MECHANISM_TYPE cipher_mechanism;
@@ -203,7 +204,8 @@
 		ok = 0;
 	}
 
-	PK11_FreeSymKey(sym_key);	
+	/* Clean up.  */
+	free_any_symkey("sym_key", &sym_key);
 	DBG(DBG_CRYPT, DBG_log("test_ctr_vector: %s %s",
 			       test->description, ok ? "passed" : "failed"));
 	return ok;
diff -Naur libreswan-3.12-orig/programs/pluto/gcm_test_vectors.c libreswan-3.12/programs/pluto/gcm_test_vectors.c
--- libreswan-3.12-orig/programs/pluto/gcm_test_vectors.c	2015-05-06 11:44:21.584466542 -0400
+++ libreswan-3.12/programs/pluto/gcm_test_vectors.c	2015-05-06 11:45:32.921301428 -0400
@@ -24,6 +24,7 @@
 
 #include "nss.h"
 #include "pk11pub.h"
+#include "crypt_symkey.h"
 
 struct gcm_test_vector {
 	const char *key;
@@ -165,14 +166,16 @@
 	}
 
 	freeanychunk(salted_iv);
-	freeanychunk(wire_iv);
 	freeanychunk(salt);
-	freeanychunk(tag);
+	freeanychunk(wire_iv);
+	freeanychunk(aad);
 	freeanychunk(plaintext);
 	freeanychunk(ciphertext);
+	freeanychunk(tag);
 	freeanychunk(text_and_tag);
 
-	PK11_FreeSymKey(sym_key);	
+	/* Clean up.  */
+	free_any_symkey("sym_key", &sym_key);
 	DBG(DBG_CRYPT, DBG_log("test_gcm_vector: %s", ok ? "passed" : "failed"));
 	return ok;
 }
diff -Naur libreswan-3.12-orig/programs/pluto/hmac.c libreswan-3.12/programs/pluto/hmac.c
--- libreswan-3.12-orig/programs/pluto/hmac.c	2014-11-06 22:52:50.000000000 -0500
+++ libreswan-3.12/programs/pluto/hmac.c	2015-05-06 11:45:32.921301428 -0400
@@ -5,8 +5,9 @@
  * Copyright (C) 2009 Paul Wouters <paul@xelerance.com>
  * Copyright (C) 2010-2012 Avesh Agarwal <avagarwa@redhat.com>
  * Copyright (C) 2012 Paul Wouters <paul@libreswan.org>
- * Copyright (C) 2012-2013 Paul Wouters <pwouters@redhat.com>
+ * Copyright (C) 2012-2015 Paul Wouters <pwouters@redhat.com>
  * Copyright (C) 2013 D. Hugh Redelmeier <hugh@mimosa.com>
+ * Copyright (C) 2015, Andrew Cagney <cagney@gnu.org>
  *
  * 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
@@ -40,272 +41,42 @@
 #include <secport.h>
 #include "lswconf.h"
 #include "lswlog.h"
+#include "crypt_symkey.h"
+#include "crypt_prf.h"
 
 /* HMAC package
  * rfc2104.txt specifies how HMAC works.
  */
 
-static CK_MECHANISM_TYPE nss_hash_mech(const struct hash_desc *hasher);
-static SECOidTag nss_hash_oid(const struct hash_desc *hasher);
-
 void hmac_init(struct hmac_ctx *ctx,
 	       const struct hash_desc *h,
 	       /*const*/ PK11SymKey *symkey)	/* NSS doesn't like const! */
 {
-	SECStatus status;
-	PK11SymKey
-		*tkey1,
-		*tkey2;
-	unsigned int klen = PK11_GetKeyLength(symkey);
-	chunk_t hmac_opad, hmac_ipad, hmac_pad;
-
-	ctx->h = h;
+	/*
+	 * Note: The SYMKEY passed to crypt_prf_init is used to
+	 * generate secure keying material from nothing.
+	 * crypt_prf_init_symkey() establishes the actual key.
+	 */
+	ctx->prf = crypt_prf_init("hmac", h, symkey);
 	ctx->hmac_digest_len = h->hash_digest_len;
-
-	/* DBG(DBG_CRYPT, DBG_log("NSS: hmac init")); */
-
-	hmac_opad = hmac_pads(HMAC_OPAD, h->hash_block_size);
-	hmac_ipad = hmac_pads(HMAC_IPAD, h->hash_block_size);
-	hmac_pad  = hmac_pads(0x00, h->hash_block_size - klen);
-
-	if (klen > h->hash_block_size) {
-		tkey1 = PK11_Derive_lsw(symkey, nss_key_derivation_mech(h),
-					NULL,
-					CKM_CONCATENATE_BASE_AND_DATA,
-					CKA_DERIVE,
-					0);
-	} else {
-		tkey1 = symkey;
-	}
-
-	tkey2 = pk11_derive_wrapper_lsw(tkey1, CKM_CONCATENATE_BASE_AND_DATA,
-					hmac_pad,
-					CKM_XOR_BASE_AND_DATA, CKA_DERIVE,
-					h->hash_block_size);
-	passert(tkey2 != NULL);
-
-	ctx->ikey = pk11_derive_wrapper_lsw(tkey2, CKM_XOR_BASE_AND_DATA,
-					    hmac_ipad, nss_hash_mech(h),
-					    CKA_DIGEST, 0);
-	passert(ctx->ikey != NULL);
-
-	ctx->okey = pk11_derive_wrapper_lsw(tkey2, CKM_XOR_BASE_AND_DATA,
-					    hmac_opad, nss_hash_mech(h),
-					    CKA_DIGEST, 0);
-	passert(ctx->okey != NULL);
-
-	if (tkey1 != symkey)
-		PK11_FreeSymKey(tkey1);
-	PK11_FreeSymKey(tkey2);
-
-	freeanychunk(hmac_opad);
-	freeanychunk(hmac_ipad);
-	freeanychunk(hmac_pad);
-	ctx->ctx_nss = PK11_CreateDigestContext(nss_hash_oid(h));
-	passert(ctx->ctx_nss != NULL);
-
-	status = PK11_DigestBegin(ctx->ctx_nss);
-	passert(status == SECSuccess);
-
-	status = PK11_DigestKey(ctx->ctx_nss, ctx->ikey);
-	passert(status == SECSuccess);
+	crypt_prf_init_symkey("symkey", ctx->prf, symkey);
+	crypt_prf_update(ctx->prf);
 }
 
 void hmac_update(struct hmac_ctx *ctx,
 		 const u_char *data, size_t data_len)
 {
-	DBG(DBG_CRYPT, DBG_dump("hmac_update data value: ", data, data_len));
-	if (data_len > 0) {
-		SECStatus status;
-
-		DBG(DBG_CRYPT, DBG_log("hmac_update: inside if"));
-		status = PK11_DigestOp(ctx->ctx_nss, data, data_len);
-		DBG(DBG_CRYPT, DBG_log("hmac_update: after digest"));
-		passert(status == SECSuccess);
-		DBG(DBG_CRYPT, DBG_log("hmac_update: after assert"));
-	}
+	crypt_prf_update_bytes("data", ctx->prf, data, data_len);
 }
 
 void hmac_final(u_char *output, struct hmac_ctx *ctx)
 {
-	unsigned int outlen;
-	SECStatus status;
-
-	status = PK11_DigestFinal(ctx->ctx_nss, output, &outlen,
-					    ctx->hmac_digest_len);
-	passert(status == SECSuccess);
-	passert(outlen == ctx->hmac_digest_len);
-	PK11_DestroyContext(ctx->ctx_nss, PR_TRUE);
-	ctx->ctx_nss = NULL;
-
-	ctx->ctx_nss = PK11_CreateDigestContext(nss_hash_oid(ctx->h));
-	passert(ctx->ctx_nss != NULL);
-
-	status = PK11_DigestBegin(ctx->ctx_nss);
-	passert(status == SECSuccess);
-
-	status = PK11_DigestKey(ctx->ctx_nss, ctx->okey);
-	passert(status == SECSuccess);
-
-	status = PK11_DigestOp(ctx->ctx_nss, output, outlen);
-	passert(status == SECSuccess);
-
-	status = PK11_DigestFinal(ctx->ctx_nss, output, &outlen,
-				  ctx->hmac_digest_len);
-	passert(status == SECSuccess);
-	passert(outlen == ctx->hmac_digest_len);
-	PK11_DestroyContext(ctx->ctx_nss, PR_TRUE);
-
-	if (ctx->ikey != NULL)
-		PK11_FreeSymKey(ctx->ikey);
-	if (ctx->okey != NULL)
-		PK11_FreeSymKey(ctx->okey);
-	/* DBG(DBG_CRYPT, DBG_log("NSS: hmac final end")); */
-}
-
-static SECOidTag nss_hash_oid(const struct hash_desc *hasher)
-{
-	SECOidTag mechanism;
-
-	switch (hasher->common.algo_id) {
-	case OAKLEY_MD5:
-		mechanism = SEC_OID_MD5;
-		break;
-	case OAKLEY_SHA1:
-		mechanism = SEC_OID_SHA1;
-		break;
-	case OAKLEY_SHA2_256:
-		mechanism = SEC_OID_SHA256;
-		break;
-	case OAKLEY_SHA2_384:
-		mechanism = SEC_OID_SHA384;
-		break;
-	case OAKLEY_SHA2_512:
-		mechanism = SEC_OID_SHA512;
-		break;
-	default:
-		libreswan_log("NSS: key derivation mechanism (hasher->common.algo_id=%d not supported",
-			hasher->common.algo_id);
-		mechanism = 0;	/* ??? what should we do to recover? */
-		break;
-	}
-	return mechanism;
-}
-
-static CK_MECHANISM_TYPE nss_hash_mech(const struct hash_desc *hasher)
-{
-	CK_MECHANISM_TYPE mechanism;
-
-	switch (hasher->common.algo_id) {
-	case OAKLEY_MD5:
-		mechanism = CKM_MD5;
-		break;
-	case OAKLEY_SHA1:
-		mechanism = CKM_SHA_1;
-		break;
-	case OAKLEY_SHA2_256:
-		mechanism = CKM_SHA256;
-		break;
-	case OAKLEY_SHA2_384:
-		mechanism = CKM_SHA384;
-		break;
-	case OAKLEY_SHA2_512:
-		mechanism = CKM_SHA512;
-		break;
-	default:
-		/* ??? surely this requires more than a DBG entry! */
-		DBG(DBG_CRYPT,
-		      DBG_log("NSS: key derivation mechanism not supported"));
-		mechanism = 0x80000000;	/* ??? what should we do to recover? */
-		break;
-	}
-	return mechanism;
-}
-
-PK11SymKey *pk11_derive_wrapper_lsw(PK11SymKey *base,
-				    CK_MECHANISM_TYPE mechanism,
-				    chunk_t data, CK_MECHANISM_TYPE target,
-				    CK_ATTRIBUTE_TYPE operation, int keySize)
-{
-	CK_KEY_DERIVATION_STRING_DATA string;
-	SECItem param;
-
-	string.pData = data.ptr;
-	string.ulLen = data.len;
-	param.data = (unsigned char*)&string;
-	param.len = sizeof(string);
-
-	return PK11_Derive(base, mechanism, &param, target, operation,
-			   keySize);
+	crypt_prf_final_bytes(ctx->prf, output, ctx->hmac_digest_len);
 }
 
-/* MUST BE THREAD-SAFE */
-PK11SymKey *PK11_Derive_lsw(PK11SymKey *base, CK_MECHANISM_TYPE mechanism,
-			     SECItem *param, CK_MECHANISM_TYPE target,
-			     CK_ATTRIBUTE_TYPE operation, int keysize)
-{
-	if (param == NULL && keysize == 0) {
-		SECOidTag oid;
-		PK11Context *ctx;
-		unsigned char dkey[HMAC_BUFSIZE * 2];
-		SECItem dkey_param;
-		SECStatus status;
-		unsigned int len;
-		CK_EXTRACT_PARAMS bs;
-		chunk_t dkey_chunk;
-
-		switch (mechanism) {
-		case CKM_SHA256_KEY_DERIVATION:
-			oid = SEC_OID_SHA256;
-			break;
-		case CKM_SHA384_KEY_DERIVATION:
-			oid = SEC_OID_SHA384;
-			break;
-		case CKM_SHA512_KEY_DERIVATION:
-			oid = SEC_OID_SHA512;
-			break;
-		default:
-			return PK11_Derive(base, mechanism, param, target,
-					   operation, keysize);
-		}
-
-		ctx = PK11_CreateDigestContext(oid);
-		passert(ctx != NULL);
-		status = PK11_DigestBegin(ctx);
-		passert(status == SECSuccess);
-		status = PK11_DigestKey(ctx, base);
-		passert(status == SECSuccess);
-		status = PK11_DigestFinal(ctx, dkey, &len, sizeof dkey);
-		passert(status == SECSuccess);
-		PK11_DestroyContext(ctx, PR_TRUE);
-
-		dkey_chunk.ptr = dkey;
-		dkey_chunk.len = len;
-
-		PK11SymKey *tkey1 = pk11_derive_wrapper_lsw(base,
-							    CKM_CONCATENATE_DATA_AND_BASE, dkey_chunk, CKM_EXTRACT_KEY_FROM_KEY, CKA_DERIVE,
-							    0);
-		passert(tkey1 != NULL);
-
-		bs = 0;
-		dkey_param.data = (unsigned char*)&bs;
-		dkey_param.len = sizeof(bs);
-		PK11SymKey *tkey2 = PK11_Derive(tkey1,
-						CKM_EXTRACT_KEY_FROM_KEY,
-						&dkey_param, target, operation,
-						len);
-		passert(tkey2 != NULL);
-
-		if (tkey1 != NULL)
-			PK11_FreeSymKey(tkey1);
-
-		return tkey2;
-
-	} else {
-		return PK11_Derive(base, mechanism, param, target, operation,
-				   keysize);
-	}
-}
+/*
+ * XXX: This should be moved to crypt_symkey.c and made private.
+ */
 
 CK_MECHANISM_TYPE nss_key_derivation_mech(const struct hash_desc *hasher)
 {
@@ -335,6 +106,11 @@
 	return mechanism;
 }
 
+/*
+ * XXX: This has nothing to do with HMAC; it should be made part of
+ * the chunk_t library code.
+ */
+
 chunk_t hmac_pads(u_char val, unsigned int len)
 {
 	chunk_t ret;
@@ -346,31 +122,3 @@
 
 	return ret;
 }
-
-void nss_symkey_log(PK11SymKey *key, const char *msg)
-{
-	if (key == NULL) {
-		/* ??? should we print this even if !DBG_CRYPT? */
-		DBG_log("NULL key %s", msg);
-	} else {
-		DBG(DBG_CRYPT, {
-			DBG_log("computed key %s with length =%d", msg,
-					       PK11_GetKeyLength(key));
-
-			if (!PK11_IsFIPS()) {
-				SECStatus status = PK11_ExtractKeyValue(key);
-
-				if (status == SECSuccess) {
-					SECItem *keydata = PK11_GetKeyData(key);
-
-					DBG_dump("value: ", keydata->data,
-						 keydata->len);
-
-					SECITEM_FreeItem(keydata, PR_TRUE);	/* ??? this was commented out.  Why? */
-				} else {
-					DBG_log("unobtainable key %s", msg);
-				}
-			}
-		});
-	}
-}
diff -Naur libreswan-3.12-orig/programs/pluto/hostpair.c libreswan-3.12/programs/pluto/hostpair.c
--- libreswan-3.12-orig/programs/pluto/hostpair.c	2014-11-06 22:52:50.000000000 -0500
+++ libreswan-3.12/programs/pluto/hostpair.c	2015-05-06 11:45:32.922301440 -0400
@@ -286,7 +286,7 @@
 					 */
 					passert(p == *pp);
 
-					terminate_connection(p->name);
+					// terminate_connection(p->name);
 					p->interface = NULL;
 
 					*pp = p->hp_next; /* advance *pp */
diff -Naur libreswan-3.12-orig/programs/pluto/ike_alg_aes.c libreswan-3.12/programs/pluto/ike_alg_aes.c
--- libreswan-3.12-orig/programs/pluto/ike_alg_aes.c	2015-05-06 11:44:21.609466836 -0400
+++ libreswan-3.12/programs/pluto/ike_alg_aes.c	2015-05-06 11:45:47.617471739 -0400
@@ -410,7 +410,11 @@
 
 void ike_alg_aes_init(void)
 {
-	bool fips = libreswan_fipsmode();
+#ifdef FIPS_CHECK
+	bool fips = libreswan_fipsproduct() || libreswan_fipskernel();
+#else
+	bool fips = FALSE;
+#endif
 	if (!fips && !test_aes_cbc(&algo_aes_cbc)) {
 		loglog(RC_LOG_SERIOUS, "CKM_AES_CBC: test failure");
 		exit_pluto(6);
diff -Naur libreswan-3.12-orig/programs/pluto/ike_alg.c libreswan-3.12/programs/pluto/ike_alg.c
--- libreswan-3.12-orig/programs/pluto/ike_alg.c	2015-05-06 11:44:21.585466554 -0400
+++ libreswan-3.12/programs/pluto/ike_alg.c	2015-05-06 11:45:32.922301440 -0400
@@ -322,3 +322,53 @@
 		ret = lookup_group(c->alg_info_esp->esp_pfsgroup);
 	return ret;
 }
+
+CK_MECHANISM_TYPE nss_encryption_mech(const struct encrypt_desc *encrypter)
+{
+	/* the best wey have for "undefined" */
+	CK_MECHANISM_TYPE mechanism = CKM_VENDOR_DEFINED;
+
+	switch (encrypter->common.algo_id) {
+	case OAKLEY_3DES_CBC:
+		mechanism = CKM_DES3_CBC;
+		break;
+#ifdef NOT_YET
+	case OAKLEY_CAST_CBC:
+		mechanism = CKM_CAST5_CBC:
+		break;
+#endif
+	case OAKLEY_AES_CBC:
+		mechanism = CKM_AES_CBC;
+		break;
+	case OAKLEY_CAMELLIA_CBC:
+		mechanism = CKM_CAMELLIA_CBC;
+		break;
+	case OAKLEY_AES_CTR:
+		mechanism = CKM_AES_CTR;
+		break;
+#ifdef NOT_YET
+	case OAKLEY_AES_CCM_8:
+	case OAKLEY_AES_CCM_12:
+	case OAKLEY_AES_CCM_16:
+		mechanism = CKM_AES_CCM;
+		break;
+#endif
+	case OAKLEY_AES_GCM_8:
+	case OAKLEY_AES_GCM_12:
+	case OAKLEY_AES_GCM_16:
+		mechanism = CKM_AES_GCM;
+		break;
+#ifdef NOT_YET
+	case OAKLEY_TWOFISH_CBC:
+		mechanism = CKM_TWOFISH_CBC;
+		break;
+#endif
+	default:
+		loglog(RC_LOG_SERIOUS,
+			"NSS: Unsupported encryption mechanism for %s",
+			strip_prefix(enum_name(&oakley_enc_names,
+				encrypter->common.algo_id), "OAKLEY_"));
+		break;
+	}
+	return mechanism;
+}
diff -Naur libreswan-3.12-orig/programs/pluto/ike_alg_camellia.c libreswan-3.12/programs/pluto/ike_alg_camellia.c
--- libreswan-3.12-orig/programs/pluto/ike_alg_camellia.c	2015-05-06 11:44:21.610466848 -0400
+++ libreswan-3.12/programs/pluto/ike_alg_camellia.c	2015-05-06 11:45:47.617471739 -0400
@@ -95,7 +95,7 @@
 void ike_alg_camellia_init(void)
 {
 #ifdef FIPS_CHECK
-	bool fips = libreswan_fipsmode();
+	bool fips = libreswan_fipsproduct() || libreswan_fipskernel();
 #else
 	bool fips = FALSE;
 #endif
diff -Naur libreswan-3.12-orig/programs/pluto/ike_alg.h libreswan-3.12/programs/pluto/ike_alg.h
--- libreswan-3.12-orig/programs/pluto/ike_alg.h	2015-05-06 11:44:21.585466554 -0400
+++ libreswan-3.12/programs/pluto/ike_alg.h	2015-05-06 11:45:32.922301440 -0400
@@ -186,5 +186,6 @@
 extern void ike_alg_sha2_init(void);
 #endif
 
+CK_MECHANISM_TYPE nss_encryption_mech(const struct encrypt_desc *encrypter);
 
 #endif /* _IKE_ALG_H */
diff -Naur libreswan-3.12-orig/programs/pluto/ikev1_prf.c libreswan-3.12/programs/pluto/ikev1_prf.c
--- libreswan-3.12-orig/programs/pluto/ikev1_prf.c	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/ikev1_prf.c	2015-05-06 11:45:32.923301452 -0400
@@ -0,0 +1,348 @@
+/*
+ * Calculate IKEv1 prf and keying material, for libreswan
+ *
+ * Copyright (C) 2007 Michael C. Richardson <mcr@xelerance.com>
+ * Copyright (C) 2010 Paul Wouters <paul@xelerance.com>
+ * Copyright (C) 2013 D. Hugh Redelmeier <hugh@mimosa.com>
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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 <stdlib.h>
+#include <stdint.h>
+
+#include "libreswan.h"
+#include "lswlog.h"
+#include "constants.h"
+#include "defs.h"
+#include "sysqueue.h"
+#include "crypto.h"
+#include "crypt_dh.h"
+#include "crypt_prf.h"
+#include "ikev1_prf.h"
+#include "ike_alg.h"
+#include "packet.h"
+#include "pluto_crypt.h"
+#include "crypt_symkey.h"
+
+/*
+ * Compute: SKEYID = prf(Ni_b | Nr_b, g^xy)
+ *
+ * MUST BE THREAD-SAFE
+ */
+PK11SymKey *ikev1_signature_skeyid(const struct hash_desc *hasher,
+				   const chunk_t Ni,
+				   const chunk_t Nr,
+				   /*const*/ PK11SymKey *dh_secret /* NSS doesn't do const */)
+{
+	struct crypt_prf *prf = crypt_prf_init("SKEYID sig", hasher, dh_secret);
+	/* key = Ni|Nr */
+	crypt_prf_init_chunk("Ni", prf, Ni);
+	crypt_prf_init_chunk("Nr", prf, Nr);
+	/* seed = g^xy */
+	crypt_prf_update(prf);
+	crypt_prf_update_symkey("g^xy", prf, dh_secret);
+	/* generate */
+	return crypt_prf_final(prf);
+}
+
+/*
+ * Compute: SKEYID = prf(pre-shared-key, Ni_b | Nr_b)
+ */
+PK11SymKey *ikev1_pre_shared_key_skeyid(const struct hash_desc *hasher,
+					chunk_t pre_shared_key,
+					chunk_t Ni, chunk_t Nr,
+					PK11SymKey *scratch)
+{
+	struct crypt_prf *prf = crypt_prf_init("SKEYID psk", hasher, scratch);
+	/* key = pre-shared-key */
+	crypt_prf_init_chunk("psk", prf, pre_shared_key);
+	/* seed = Ni_b | Nr_b */
+	crypt_prf_update(prf);
+	crypt_prf_update_chunk("Ni", prf, Ni);
+	crypt_prf_update_chunk("Nr", prf, Nr);
+	/* generate */
+	return crypt_prf_final(prf);
+}
+
+/*
+ * SKEYID_d = prf(SKEYID, g^xy | CKY-I | CKY-R | 0)
+ */
+PK11SymKey *ikev1_skeyid_d(const struct hash_desc *hasher,
+			   PK11SymKey *skeyid,
+			   PK11SymKey *dh_secret,
+			   chunk_t cky_i, chunk_t cky_r)
+{
+	struct crypt_prf *prf = crypt_prf_init("SKEYID_d", hasher, dh_secret);
+	/* key = SKEYID */
+	crypt_prf_init_symkey("SKEYID", prf, skeyid);
+	/* seed = g^xy | CKY-I | CKY-R | 0 */
+	crypt_prf_update(prf);
+	crypt_prf_update_symkey("g^xy", prf, dh_secret);
+	crypt_prf_update_chunk("CKI_i", prf, cky_i);
+	crypt_prf_update_chunk("CKI_r", prf, cky_r);
+	crypt_prf_update_byte("0", prf, 0);
+	/* generate */
+	return crypt_prf_final(prf);
+}
+
+/*
+ * SKEYID_a = prf(SKEYID, SKEYID_d | g^xy | CKY-I | CKY-R | 1)
+ */
+PK11SymKey *ikev1_skeyid_a(const struct hash_desc *hasher,
+			   PK11SymKey *skeyid,
+			   PK11SymKey *skeyid_d, PK11SymKey *dh_secret,
+			   chunk_t cky_i, chunk_t cky_r)
+{
+	struct crypt_prf *prf = crypt_prf_init("SKEYID_a", hasher, dh_secret);
+	/* key = SKEYID */
+	crypt_prf_init_symkey("SKEYID", prf, skeyid);
+	/* seed = SKEYID_d | g^xy | CKY-I | CKY-R | 1 */
+	crypt_prf_update(prf);
+	crypt_prf_update_symkey("SKEYID_d", prf, skeyid_d);
+	crypt_prf_update_symkey("g^xy", prf, dh_secret);
+	crypt_prf_update_chunk("CKI_i", prf, cky_i);
+	crypt_prf_update_chunk("CKI_r", prf, cky_r);
+	crypt_prf_update_byte("1", prf, 1);
+	/* generate */
+	return crypt_prf_final(prf);
+}
+
+/*
+ * SKEYID_e = prf(SKEYID, SKEYID_a | g^xy | CKY-I | CKY-R | 2)
+ */
+PK11SymKey *ikev1_skeyid_e(const struct hash_desc *hasher,
+			   PK11SymKey *skeyid,
+			   PK11SymKey *skeyid_a, PK11SymKey *dh_secret,
+			   chunk_t cky_i, chunk_t cky_r)
+{
+	struct crypt_prf *prf = crypt_prf_init("SKEYID_e", hasher, dh_secret);
+	/* key = SKEYID */
+	crypt_prf_init_symkey("SKEYID", prf, skeyid);
+	/* seed = SKEYID_a | g^xy | CKY-I | CKY-R | 2 */
+	crypt_prf_update(prf);
+	crypt_prf_update_symkey("SKEYID_a", prf, skeyid_a);
+	crypt_prf_update_symkey("g^xy", prf, dh_secret);
+	crypt_prf_update_chunk("CKI_i", prf, cky_i);
+	crypt_prf_update_chunk("CKI_r", prf, cky_r);
+	crypt_prf_update_byte("2", prf, 2);
+	/* generate */
+	return crypt_prf_final(prf);
+}
+
+static PK11SymKey *appendix_b_keymat_e(const struct hash_desc *hasher,
+				       const struct encrypt_desc *encrypter, 
+				       PK11SymKey *skeyid_e,
+				       unsigned required_keymat)
+{
+	if (PK11_GetKeyLength(skeyid_e) >= required_keymat) {
+		return encrypt_key_from_symkey_bytes(skeyid_e, encrypter, 0,
+						     required_keymat);
+	}
+	/* K1 = prf(skeyid_e, 0) */
+	PK11SymKey *keymat;
+	{
+		struct crypt_prf *prf = crypt_prf_init("appendix_b",
+						       hasher, skeyid_e);
+		crypt_prf_init_symkey("SKEYID_e", prf, skeyid_e);
+		crypt_prf_update(prf);
+		crypt_prf_update_byte("0", prf, 0);
+		keymat = crypt_prf_final(prf);
+	}
+
+	/* make a copy to keep things easy */
+	PK11SymKey *old_k = key_from_symkey_bytes(keymat, 0, PK11_GetKeyLength(keymat));
+	while (PK11_GetKeyLength(keymat) < required_keymat) {
+		/* Kn = prf(skeyid_e, Kn-1) */
+		struct crypt_prf *prf = crypt_prf_init("SKEYID_e", hasher, skeyid_e);
+		crypt_prf_init_symkey("SKEYID_e", prf, skeyid_e);
+		crypt_prf_update(prf);
+		crypt_prf_update_symkey("old_k", prf, old_k);
+		PK11SymKey *new_k = crypt_prf_final(prf);
+		append_symkey_symkey(hasher, &keymat, new_k);
+		free_any_symkey("old_k#N", &old_k);
+		old_k = new_k;
+	} 
+	free_any_symkey("old_k#final", &old_k);
+	PK11SymKey *cryptkey = encrypt_key_from_symkey_bytes(keymat, encrypter, 0,
+							     required_keymat);
+	free_any_symkey("keymat", &keymat);
+	return cryptkey;
+}
+
+/* Generate the SKEYID_* and new IV
+ * See draft-ietf-ipsec-ike-01.txt 4.1
+ */
+/* MUST BE THREAD-SAFE */
+static void calc_skeyids_iv(struct pcr_skeyid_q *skq,
+			    /*const*/ PK11SymKey *shared,	/* NSS doesn't do const */
+			    const size_t keysize,	/* = st->st_oakley.enckeylen/BITS_PER_BYTE; */
+			    PK11SymKey **skeyid_out,	/* output */
+			    PK11SymKey **skeyid_d_out,	/* output */
+			    PK11SymKey **skeyid_a_out,	/* output */
+			    PK11SymKey **skeyid_e_out,	/* output */
+			    chunk_t *new_iv,	/* output */
+			    PK11SymKey **enc_key_out	/* output */
+			    )
+{
+	oakley_auth_t auth = skq->auth;
+	oakley_hash_t hash = skq->prf_hash;
+	const struct hash_desc *hasher = crypto_get_hasher(hash);
+	chunk_t ni;
+	chunk_t nr;
+	chunk_t gi;
+	chunk_t gr;
+	chunk_t icookie;
+	chunk_t rcookie;
+	const struct encrypt_desc *encrypter = skq->encrypter;
+
+	/* this doesn't allocate any memory */
+	setchunk_from_wire(gi, skq, &skq->gi);
+	setchunk_from_wire(gr, skq, &skq->gr);
+	setchunk_from_wire(ni, skq, &skq->ni);
+	setchunk_from_wire(nr, skq, &skq->nr);
+	setchunk_from_wire(icookie, skq, &skq->icookie);
+	setchunk_from_wire(rcookie, skq, &skq->rcookie);
+
+	/* Generate the SKEYID */
+	PK11SymKey *skeyid;
+	switch (auth) {
+	case OAKLEY_PRESHARED_KEY:
+		{
+			chunk_t pss;
+
+			setchunk_from_wire(pss, skq, &skq->pss);
+			skeyid = ikev1_pre_shared_key_skeyid(hasher, pss,
+							     ni, nr, shared);
+		}
+		break;
+
+	case OAKLEY_RSA_SIG:
+		skeyid = ikev1_signature_skeyid(hasher, ni, nr, shared);
+		break;
+
+	/* Not implemented */
+	case OAKLEY_DSS_SIG:
+	case OAKLEY_RSA_ENC:
+	case OAKLEY_RSA_REVISED_MODE:
+	case OAKLEY_ECDSA_P256:
+	case OAKLEY_ECDSA_P384:
+	case OAKLEY_ECDSA_P521:
+	default:
+		bad_case(auth);
+	}
+
+	/* generate SKEYID_* from SKEYID */
+	PK11SymKey *skeyid_d = ikev1_skeyid_d(hasher, skeyid, shared,
+					      icookie, rcookie);
+	PK11SymKey *skeyid_a = ikev1_skeyid_a(hasher, skeyid, skeyid_d,
+					      shared, icookie, rcookie);
+	PK11SymKey *skeyid_e = ikev1_skeyid_e(hasher, skeyid, skeyid_a,
+					      shared, icookie, rcookie);
+
+	PK11SymKey *enc_key = appendix_b_keymat_e(hasher, encrypter,
+						  skeyid_e, keysize);
+	
+	*skeyid_out = skeyid;
+	*skeyid_d_out = skeyid_d;
+	*skeyid_a_out = skeyid_a;
+	*skeyid_e_out = skeyid_e;
+	*enc_key_out = enc_key;
+	
+	DBG(DBG_CRYPT, DBG_log("NSS: pointers skeyid_d %p,  skeyid_a %p,  skeyid_e %p,  enc_key %p",
+			       skeyid_d, skeyid_a, skeyid_e, enc_key));
+
+	/* generate IV */
+	{
+		union hash_ctx hash_ctx;
+
+		new_iv->len = hasher->hash_digest_len;
+		new_iv->ptr = alloc_bytes(new_iv->len, "calculated new iv");
+
+		DBG(DBG_CRYPT, {
+			    DBG_dump_chunk("DH_i:", gi);
+			    DBG_dump_chunk("DH_r:", gr);
+		    });
+		hasher->hash_init(&hash_ctx);
+		hasher->hash_update(&hash_ctx, gi.ptr, gi.len);
+		hasher->hash_update(&hash_ctx, gr.ptr, gr.len);
+		hasher->hash_final(new_iv->ptr, &hash_ctx);
+		DBG(DBG_CRYPT, DBG_log("end of IV generation"));
+	}
+}
+
+/* MUST BE THREAD-SAFE */
+void calc_dh_iv(struct pluto_crypto_req *r)
+{
+	struct pcr_skeyid_r *skr = &r->pcr_d.dhr;
+	struct pcr_skeyid_q dhq;
+	const struct oakley_group_desc *group;
+	PK11SymKey *shared;
+	chunk_t g;
+	SECKEYPrivateKey *ltsecret;
+	PK11SymKey
+		*skeyid,
+		*skeyid_d,
+		*skeyid_a,
+		*skeyid_e,
+		*enc_key;
+	chunk_t new_iv;
+	SECKEYPublicKey *pubk;
+
+	/* copy the request, since the reply will re-use the memory of the r->pcr_d.dhq */
+	memcpy(&dhq, &r->pcr_d.dhq, sizeof(r->pcr_d.dhq));
+
+	/* clear out the reply */
+	zero(skr);
+	INIT_WIRE_ARENA(*skr);
+
+	group = lookup_group(dhq.oakley_group);
+	passert(group != NULL);
+
+	ltsecret = dhq.secret;
+	pubk = dhq.pubk;
+
+	/* now calculate the (g^x)(g^y) ---
+	 * need gi on responder, gr on initiator
+	 */
+
+	setchunk_from_wire(g, &dhq, dhq.role == O_RESPONDER ? &dhq.gi : &dhq.gr);
+
+	DBG(DBG_CRYPT,
+	    DBG_dump_chunk("peer's g: ", g));
+
+	shared = calc_dh_shared(g, ltsecret, group, pubk);
+
+	zero(&new_iv);
+
+	/* okay, so now calculate IV */
+	calc_skeyids_iv(&dhq,
+			shared,
+			dhq.key_size,
+			&skeyid,
+			&skeyid_d,
+			&skeyid_a,
+			&skeyid_e,
+			&new_iv,
+			&enc_key);
+
+	skr->shared = shared;
+	skr->skeyid = skeyid;
+	skr->skeyid_d = skeyid_d;
+	skr->skeyid_a = skeyid_a;
+	skr->skeyid_e = skeyid_e;
+	skr->enc_key = enc_key;
+
+
+	WIRE_CLONE_CHUNK(*skr, new_iv, new_iv);
+	freeanychunk(new_iv);
+}
diff -Naur libreswan-3.12-orig/programs/pluto/ikev1_prf.h libreswan-3.12/programs/pluto/ikev1_prf.h
--- libreswan-3.12-orig/programs/pluto/ikev1_prf.h	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/ikev1_prf.h	2015-05-06 11:45:32.923301452 -0400
@@ -0,0 +1,66 @@
+/*
+ * Calculate IKEv1 prf and keying material, for libreswan
+ *
+ * Copyright (C) 2007 Michael C. Richardson <mcr@xelerance.com>
+ * Copyright (C) 2010 Paul Wouters <paul@xelerance.com>
+ * Copyright (C) 2013 D. Hugh Redelmeier <hugh@mimosa.com>
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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 ikev1_prf_h
+#define ikev1_prf_h
+
+/*
+ * IKE SA SKEYID for authentication
+ *
+ * Be warned, this is not DSS (even though NIST call it Digital
+ * Signature Algorithm).  It is used by RSA-SIG.
+ */
+PK11SymKey *ikev1_signature_skeyid(const struct hash_desc *hasher,
+				   const chunk_t Ni_b, const chunk_t Nr_b,
+				   PK11SymKey *dh_secret);
+
+PK11SymKey *ikev1_pre_shared_key_skeyid(const struct hash_desc *hasher,
+					chunk_t pre_shared_key,
+					chunk_t Ni_b, chunk_t Nr_b,
+					PK11SymKey *scratch);
+
+/*
+ * Authenticated keying material.
+ *
+ *  Perhaps this should just return a struct?
+ */
+
+PK11SymKey *ikev1_skeyid_d(const struct hash_desc *hasher,
+			   PK11SymKey *skeyid,
+			   PK11SymKey *dh_secret,
+			   chunk_t cky_i, chunk_t cky_r);
+
+PK11SymKey *ikev1_skeyid_a(const struct hash_desc *hasher,
+			   PK11SymKey *skeyid,
+			   PK11SymKey *skeyid_d, PK11SymKey *dh_secret,
+			   chunk_t cky_i, chunk_t cky_r);
+
+PK11SymKey *ikev1_skeyid_e(const struct hash_desc *hasher,
+			   PK11SymKey *skeyid,
+			   PK11SymKey *skeyid_a, PK11SymKey *dh_secret,
+			   chunk_t cky_i, chunk_t cky_r);
+
+/*
+ * Old way.
+ */
+struct pluto_crypto_req;
+
+void calc_dh_iv(struct pluto_crypto_req *r);
+
+#endif
diff -Naur libreswan-3.12-orig/programs/pluto/ikev1_quick.c libreswan-3.12/programs/pluto/ikev1_quick.c
--- libreswan-3.12-orig/programs/pluto/ikev1_quick.c	2014-11-06 22:52:50.000000000 -0500
+++ libreswan-3.12/programs/pluto/ikev1_quick.c	2015-05-06 11:45:32.923301452 -0400
@@ -70,6 +70,7 @@
 #include "plutoalg.h"
 
 #include "pluto_crypt.h"
+#include "crypt_prf.h"
 #include "ikev1.h"
 #include "ikev1_quick.h"
 #include "ikev1_continuations.h"
@@ -470,13 +471,8 @@
 
 		for (i = 0;; ) {
 			if (st->st_shared_nss != NULL) {
-				/* PFS: include the g^xy */
-				SECStatus s;
-
-				s = PK11_DigestKey(ctx_me.ctx_nss, st->st_shared_nss);
-				passert(s == SECSuccess);
-				s = PK11_DigestKey(ctx_peer.ctx_nss, st->st_shared_nss);
-				passert(s == SECSuccess);
+				crypt_prf_update_symkey("g^xy", ctx_me.prf, st->st_shared_nss);
+				crypt_prf_update_symkey("g^xy", ctx_peer.prf, st->st_shared_nss);
 			}
 			hmac_update(&ctx_me, &protoid, sizeof(protoid));
 			hmac_update(&ctx_peer, &protoid, sizeof(protoid));
diff -Naur libreswan-3.12-orig/programs/pluto/ikev2_crypto.c libreswan-3.12/programs/pluto/ikev2_crypto.c
--- libreswan-3.12-orig/programs/pluto/ikev2_crypto.c	2014-11-06 22:52:50.000000000 -0500
+++ libreswan-3.12/programs/pluto/ikev2_crypto.c	2015-05-06 11:45:32.924301463 -0400
@@ -49,15 +49,16 @@
 #include "crypto.h" /* requires sha1.h and md5.h */
 #include "demux.h"
 #include "ikev2.h"
-#include "ikev2_prfplus.h"
+#include "ikev2_prf.h"
 #include "ike_alg.h"
 #include "alg_info.h"
 #include "kernel_alg.h"
+#include "crypt_symkey.h"
+#include "ikev2_prf.h"
+
 
 void ikev2_derive_child_keys(struct state *st, enum phase1_role role)
 {
-	struct v2prf_stuff childsacalc;
-
 	chunk_t ikeymat, rkeymat;
 	/* ??? note assumption that AH and ESP cannot be combined */
 	struct ipsec_proto_info *ipi =
@@ -81,17 +82,6 @@
 	passert(ei != NULL);
 	ipi->attrs.transattrs.ei = ei;
 
-	zero(&childsacalc);
-	childsacalc.prf_hasher = st->st_oakley.prf_hasher;
-
-	setchunk(childsacalc.ni, st->st_ni.ptr, st->st_ni.len);
-	setchunk(childsacalc.nr, st->st_nr.ptr, st->st_nr.len);
-	childsacalc.spii.len = 0;
-	childsacalc.spir.len = 0;
-
-	childsacalc.counter[0] = 1;
-	childsacalc.skeyseed = st->st_skey_d_nss;
-
 	/* ??? no account is taken of AH */
 	/* transid is same as esp_ealg_id */
 	switch (ei->transid) {
@@ -150,11 +140,20 @@
 	 *    salt (AES_GCM_SALT_BYTES)
 	 */
 
-	v2genbytes(&ikeymat, ipi->keymat_len,
-		   "initiator keys", &childsacalc);
-
-	v2genbytes(&rkeymat, ipi->keymat_len,
-		   "responder keys", &childsacalc);
+	chunk_t ni;
+	chunk_t nr;
+	setchunk(ni, st->st_ni.ptr, st->st_ni.len);
+	setchunk(nr, st->st_nr.ptr, st->st_nr.len);
+
+	PK11SymKey *keymat = ikev2_child_sa_keymat(st->st_oakley.prf_hasher,
+						st->st_skey_d_nss,
+						NULL/*dh*/, ni, nr,
+						ipi->keymat_len * 2); 
+	ikeymat = chunk_from_symkey_bytes("initiator keys", keymat,
+					0, ipi->keymat_len);
+	rkeymat = chunk_from_symkey_bytes("initiator keys", keymat,
+					ipi->keymat_len, ipi->keymat_len);
+	free_any_symkey("keymat", &keymat);
 
 	if (role != O_INITIATOR) {
 		DBG(DBG_CRYPT, {
diff -Naur libreswan-3.12-orig/programs/pluto/ikev2_prf.c libreswan-3.12/programs/pluto/ikev2_prf.c
--- libreswan-3.12-orig/programs/pluto/ikev2_prf.c	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/ikev2_prf.c	2015-05-06 11:45:32.924301463 -0400
@@ -0,0 +1,405 @@
+/*
+ * Calculate IKEv2 prf and keying material, for libreswan
+ *
+ * Copyright (C) 2007 Michael C. Richardson <mcr@xelerance.com>
+ * Copyright (C) 2010 Paul Wouters <paul@xelerance.com>
+ * Copyright (C) 2013 D. Hugh Redelmeier <hugh@mimosa.com>
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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.
+ *
+ * This code was developed with the support of Redhat corporation.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include <libreswan.h>
+
+#include "sysdep.h"
+#include "constants.h"
+#include "defs.h"
+#include "packet.h"
+#include "demux.h"
+#include "crypto.h"
+#include "rnd.h"
+#include "state.h"
+#include "pluto_crypt.h"
+#include "lswlog.h"
+#include "log.h"
+#include "timer.h"
+#include "ike_alg.h"
+#include "id.h"
+#include "secrets.h"
+#include "keys.h"
+#include "ikev2_prf.h"
+#include "crypt_prf.h"
+#include "crypt_dh.h"
+#include "crypt_symkey.h"
+
+/*
+ * IKEv2 - RFC4306 2.14 SKEYSEED - calculation.
+ */
+
+/* MUST BE THREAD-SAFE */
+static void calc_skeyseed_v2(struct pcr_skeyid_q *skq,
+			     PK11SymKey *shared,
+			     const size_t key_size,
+			     const size_t salt_size,
+			     PK11SymKey **skeyseed_out,
+			     PK11SymKey **SK_d_out,
+			     PK11SymKey **SK_ai_out,
+			     PK11SymKey **SK_ar_out,
+			     PK11SymKey **SK_ei_out,
+			     PK11SymKey **SK_er_out,
+			     PK11SymKey **SK_pi_out,
+			     PK11SymKey **SK_pr_out,
+			     chunk_t *initiator_salt_out,
+			     chunk_t *responder_salt_out
+			     )
+			     
+{
+	DBG(DBG_CRYPT, DBG_log("NSS: Started key computation"));
+
+	PK11SymKey
+		*skeyseed_k,
+		*SK_d_k,
+		*SK_ai_k,
+		*SK_ar_k,
+		*SK_ei_k,
+		*SK_er_k,
+		*SK_pi_k,
+		*SK_pr_k;
+	chunk_t initiator_salt;
+	chunk_t responder_salt;
+	
+	
+
+	/* this doesn't take any memory, it's just moving pointers around */
+	chunk_t ni;
+	chunk_t nr;
+	chunk_t spii;
+	chunk_t spir;
+	setchunk_from_wire(ni, skq, &skq->ni);
+	setchunk_from_wire(nr, skq, &skq->nr);
+	setchunk_from_wire(spii, skq, &skq->icookie);
+	setchunk_from_wire(spir, skq, &skq->rcookie);
+
+	DBG(DBG_CONTROLMORE,
+	    DBG_log("calculating skeyseed using prf=%s integ=%s cipherkey-size=%zu salt-size=%zu",
+		    enum_name(&ikev2_trans_type_prf_names, skq->prf_hash),
+		    enum_name(&ikev2_trans_type_integ_names, skq->integ_hash),
+		    key_size, salt_size));
+
+	const struct hash_desc *prf_hasher = (struct hash_desc *)
+		ikev2_alg_find(IKE_ALG_HASH, skq->prf_hash);
+	passert(prf_hasher != NULL);
+
+	const struct encrypt_desc *encrypter = skq->encrypter;
+	passert(encrypter != NULL);
+
+	/* generate SKEYSEED from key=(Ni|Nr), hash of shared */
+	skeyseed_k = ikev2_ike_sa_skeyseed(prf_hasher, ni, nr, shared);
+	passert(skeyseed_k != NULL);
+	
+	/* now we have to generate the keys for everything */
+
+	/* need to know how many bits to generate */
+	/* SK_d needs PRF hasher key bytes */
+	/* SK_p needs PRF hasher*2 key bytes */
+	/* SK_e needs key_size*2 key bytes */
+	/* ..._salt needs salt_size*2 bytes */
+	/* SK_a needs integ's key size*2 bytes */
+
+	int skd_bytes = prf_hasher->hash_key_size;
+	int skp_bytes = prf_hasher->hash_key_size;
+	const struct hash_desc *integ_hasher =
+		(struct hash_desc *)ikev2_alg_find(IKE_ALG_INTEG, skq->integ_hash);
+	int integ_size = integ_hasher != NULL ? integ_hasher->hash_key_size : 0;
+	size_t total_keysize = skd_bytes + 2*skp_bytes + 2*key_size + 2*salt_size + 2*integ_size;
+	PK11SymKey *finalkey = ikev2_ike_sa_keymat(prf_hasher, skeyseed_k,
+						   ni, nr, spii, spir,
+						   total_keysize);
+
+	size_t next_byte = 0;
+
+	SK_d_k = key_from_symkey_bytes(finalkey, next_byte, skd_bytes);
+	next_byte += skd_bytes;
+
+	SK_ai_k = key_from_symkey_bytes(finalkey, next_byte, integ_size);
+	next_byte += integ_size;
+
+	SK_ar_k = key_from_symkey_bytes(finalkey, next_byte, integ_size);
+	next_byte += integ_size;
+
+	/* The encryption key and salt are extracted together. */
+	SK_ei_k = encrypt_key_from_symkey_bytes(finalkey, encrypter,
+						next_byte, key_size);
+	next_byte += key_size;
+	initiator_salt = chunk_from_symkey_bytes("initiator salt", finalkey,
+						 next_byte, salt_size);
+	next_byte += salt_size;
+
+	/* The encryption key and salt are extracted together. */	
+	SK_er_k = encrypt_key_from_symkey_bytes(finalkey, encrypter,
+						next_byte, key_size);
+	next_byte += key_size;
+	responder_salt = chunk_from_symkey_bytes("responder salt", finalkey,
+						 next_byte, salt_size);
+	next_byte += salt_size;
+
+	SK_pi_k = key_from_symkey_bytes(finalkey, next_byte, skp_bytes);
+	
+	
+	
+	next_byte += skp_bytes;
+
+	SK_pr_k = key_from_symkey_bytes(finalkey, next_byte, skp_bytes);
+	
+	
+	
+	next_byte += skp_bytes;
+
+	DBG(DBG_CRYPT,
+	    DBG_log("NSS ikev2: finished computing individual keys for IKEv2 SA"));
+	free_any_symkey("finalkey", &finalkey);
+
+	*skeyseed_out = skeyseed_k;
+	*SK_d_out = SK_d_k;
+	*SK_ai_out = SK_ai_k;
+	*SK_ar_out = SK_ar_k;
+	*SK_ei_out = SK_ei_k;
+	*SK_er_out = SK_er_k;
+	*SK_pi_out = SK_pi_k;
+	*SK_pr_out = SK_pr_k;
+	*initiator_salt_out = initiator_salt;
+	*responder_salt_out = responder_salt;
+	
+	
+
+	DBG(DBG_PRIVATE,
+	    DBG_log("calc_skeyseed_v2 pointers: shared %p, skeyseed %p, SK_d %p, SK_ai %p, SK_ar %p, SK_ei %p, SK_er %p, SK_pi %p, SK_pr %p",
+		    shared, skeyseed_k, SK_d_k, SK_ai_k, SK_ar_k, SK_ei_k, SK_er_k, SK_pi_k, SK_pr_k);
+	    DBG_dump_chunk("calc_skeyseed_v2 initiator salt", initiator_salt);
+	    DBG_dump_chunk("calc_skeyseed_v2 responder salt", responder_salt);
+	   );
+	    
+}
+
+/* MUST BE THREAD-SAFE */
+void calc_dh_v2(struct pluto_crypto_req *r)
+{
+	struct pcr_skeycalc_v2_r *skr = &r->pcr_d.dhv2;
+	struct pcr_skeyid_q dhq;
+	const struct oakley_group_desc *group;
+	PK11SymKey *shared;
+	chunk_t g;
+	SECKEYPrivateKey *ltsecret;
+	PK11SymKey *skeyseed;
+	PK11SymKey
+		*SK_d,
+		*SK_ai,
+		*SK_ar,
+		*SK_ei,
+		*SK_er,
+		*SK_pi,
+		*SK_pr;
+	chunk_t initiator_salt;
+	chunk_t responder_salt;
+	
+	
+	SECKEYPublicKey *pubk;
+
+	/* copy the request, since the reply will re-use the memory of the r->pcr_d.dhq */
+	memcpy(&dhq, &r->pcr_d.dhq, sizeof(r->pcr_d.dhq));
+
+	/* clear out the reply */
+	zero(skr);
+	INIT_WIRE_ARENA(*skr);
+
+	group = lookup_group(dhq.oakley_group);
+	passert(group != NULL);
+
+	ltsecret = dhq.secret;
+	pubk = dhq.pubk;
+
+	/* now calculate the (g^x)(g^y) --- need gi on responder, gr on initiator */
+
+	setchunk_from_wire(g, &dhq, dhq.role == O_RESPONDER ? &dhq.gi : &dhq.gr);
+
+	DBG(DBG_CRYPT, DBG_dump_chunk("peer's g: ", g));
+
+	shared = calc_dh_shared(g, ltsecret, group, pubk);
+
+	/* okay, so now all the shared key material */
+	calc_skeyseed_v2(&dhq,	/* input */
+			 shared,	/* input */
+			 dhq.key_size,	/* input */
+			 dhq.salt_size, /* input */
+
+			 &skeyseed,	/* output */
+			 &SK_d,	/* output */
+			 &SK_ai,	/* output */
+			 &SK_ar,	/* output */
+			 &SK_ei,	/* output */
+			 &SK_er,	/* output */
+			 &SK_pi,	/* output */
+			 &SK_pr,	/* output */
+			 &initiator_salt, /* output */
+			 &responder_salt /* output */
+			 );
+			 
+
+	skr->shared = shared;
+	skr->skeyseed = skeyseed;
+	skr->skeyid_d = SK_d;
+	skr->skeyid_ai = SK_ai;
+	skr->skeyid_ar = SK_ar;
+	skr->skeyid_ei = SK_ei;
+	skr->skeyid_er = SK_er;
+	skr->skeyid_pi = SK_pi;
+	skr->skeyid_pr = SK_pr;
+	skr->skey_initiator_salt = initiator_salt;
+	skr->skey_responder_salt = responder_salt;
+	
+	
+}
+
+static PK11SymKey *ikev2_prfplus(const struct hash_desc *hasher,
+				 PK11SymKey *key, PK11SymKey *seed,
+				 size_t required_keymat)
+{
+	uint8_t count = 1;
+
+	/* T1(prfplus) = prf(KEY, SEED|1) */
+	PK11SymKey *prfplus;
+	{
+		struct crypt_prf *prf = crypt_prf_init("prf+0",
+						       hasher, key);
+		crypt_prf_init_symkey("key", prf, key);
+		crypt_prf_update(prf);
+		crypt_prf_update_symkey("seed", prf, seed);
+		crypt_prf_update_byte("1++", prf, count++);
+		prfplus = crypt_prf_final(prf);
+	}
+
+	/* make a copy to keep things easy */
+	PK11SymKey *old_t = key_from_symkey_bytes(prfplus, 0, PK11_GetKeyLength(prfplus));
+	while (PK11_GetKeyLength(prfplus) < required_keymat) {
+		/* Tn = prf(KEY, Tn-1|SEED|n) */
+		struct crypt_prf *prf = crypt_prf_init("prf+N",
+						       hasher, key);
+		crypt_prf_init_symkey("key", prf, key);
+		crypt_prf_update(prf);
+		crypt_prf_update_symkey("old_t", prf, old_t);
+		crypt_prf_update_symkey("seed", prf, seed);
+		crypt_prf_update_byte("N++", prf, count++);
+		PK11SymKey *new_t = crypt_prf_final(prf);
+		append_symkey_symkey(hasher, &prfplus, new_t);
+		free_any_symkey("old_t[N]", &old_t);
+		old_t = new_t;
+	}
+	free_any_symkey("old_t[final]", &old_t);
+	return prfplus;
+}
+
+/*
+ * SKEYSEED = prf(Ni | Nr, g^ir)
+ */
+PK11SymKey *ikev2_ike_sa_skeyseed(const struct hash_desc *hasher,
+				  const chunk_t Ni, const chunk_t Nr,
+				  PK11SymKey *dh_secret)
+{
+	struct crypt_prf *prf = crypt_prf_init("ike sa SKEYSEED",
+					       hasher, dh_secret);
+	/* key = Ni|Nr */
+	crypt_prf_init_chunk("Ni", prf, Ni);
+	crypt_prf_init_chunk("Nr", prf, Nr);
+	/* seed = g^ir */
+	crypt_prf_update(prf);
+	/* generate */
+	crypt_prf_update_symkey("g^ir", prf, dh_secret);
+	return crypt_prf_final(prf);
+}
+
+/*
+ * SKEYSEED = prf(SK_d (old), g^ir (new) | Ni | Nr)
+ */
+PK11SymKey *ikev2_ike_sa_rekey_skeyseed(const struct hash_desc *hasher,
+					PK11SymKey *SK_d_old,
+					PK11SymKey *new_dh_secret,
+					const chunk_t Ni, const chunk_t Nr)
+{
+	struct crypt_prf *prf = crypt_prf_init("ike sa rekey skeyseed",
+					       hasher, new_dh_secret);
+	/* key = SK_d (old) */
+	crypt_prf_init_symkey("SK_d (old)", prf, SK_d_old);
+	/* seed: g^ir (new) | Ni | Nr) */
+	crypt_prf_update(prf);
+	crypt_prf_update_symkey("g^ir (new)", prf, new_dh_secret);
+	crypt_prf_update_chunk("Ni", prf, Ni);
+	crypt_prf_update_chunk("Nr", prf, Nr);
+	/* generate */
+	return crypt_prf_final(prf);
+}
+
+/*
+ * Compute: prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr)
+ */
+PK11SymKey *ikev2_ike_sa_keymat(const struct hash_desc *hasher,
+				PK11SymKey *skeyseed,
+				const chunk_t Ni, const chunk_t Nr,
+				const chunk_t SPIi, const chunk_t SPIr,
+				size_t required_bytes)
+{
+	PK11SymKey *data = symkey_from_chunk(skeyseed, Ni);
+	append_symkey_chunk(hasher, &data, Nr);
+	append_symkey_chunk(hasher, &data, SPIi);
+	append_symkey_chunk(hasher, &data, SPIr);
+	PK11SymKey *prfplus = ikev2_prfplus(hasher, skeyseed, data,
+					    required_bytes);
+	free_any_symkey(__func__, &data);
+	return prfplus;
+}
+
+/*
+ * Compute: prf+(SK_d, [ g^ir (new) | ] Ni | Nr)
+ */
+PK11SymKey *ikev2_child_sa_keymat(const struct hash_desc *hasher,
+				  PK11SymKey *SK_d,
+				  PK11SymKey *new_dh_secret,
+				  const chunk_t Ni, const chunk_t Nr,
+				  size_t required_bytes)
+{
+	PK11SymKey *data;
+	if (new_dh_secret == NULL) {
+		data = symkey_from_chunk(SK_d, Ni);
+		append_symkey_chunk(hasher, &data, Nr);
+	} else {
+		data = concat_symkey_chunk(hasher, new_dh_secret, Ni);
+		append_symkey_chunk(hasher, &data, Nr);
+	}
+	PK11SymKey *prfplus = ikev2_prfplus(hasher, SK_d, data,
+					    required_bytes);
+	free_any_symkey(__func__, &data);
+	return prfplus;
+}
diff -Naur libreswan-3.12-orig/programs/pluto/ikev2_prf.h libreswan-3.12/programs/pluto/ikev2_prf.h
--- libreswan-3.12-orig/programs/pluto/ikev2_prf.h	1969-12-31 19:00:00.000000000 -0500
+++ libreswan-3.12/programs/pluto/ikev2_prf.h	2015-05-06 11:45:32.924301463 -0400
@@ -0,0 +1,58 @@
+/*
+ * Calculate IKEv2 prf and keying material, for libreswan
+ *
+ * Copyright (C) 2007 Michael C. Richardson <mcr@xelerance.com>
+ * Copyright (C) 2010 Paul Wouters <paul@xelerance.com>
+ * Copyright (C) 2013 D. Hugh Redelmeier <hugh@mimosa.com>
+ * Copyright (C) 2015 Andrew Cagney <cagney@gnu.org>
+ *
+ * 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 _IKEV2_PRF_H
+#define _IKEV2_PRF_H
+
+/*
+ * IKE SA
+ */
+PK11SymKey *ikev2_ike_sa_skeyseed(const struct hash_desc *prf_hasher,
+				  const chunk_t Ni, const chunk_t Nr,
+				  PK11SymKey *dh_secret);
+
+PK11SymKey *ikev2_ike_sa_rekey_skeyseed(const struct hash_desc *prf_hasher,
+					PK11SymKey *old_SK_d,
+					PK11SymKey *new_dh_secret,
+					const chunk_t Ni, const chunk_t Nr);
+
+PK11SymKey *ikev2_ike_sa_keymat(const struct hash_desc *prf_hasher,
+				PK11SymKey *skeyseed,
+				const chunk_t Ni, const chunk_t Nr,
+				const chunk_t SPIi, const chunk_t SPIr,
+				size_t required_bytes);
+
+/*
+ * Child SA
+ */
+PK11SymKey *ikev2_child_sa_keymat(const struct hash_desc *prf_hasher,
+				  PK11SymKey *SK_d,
+				  PK11SymKey *new_dh_secret,
+				  const chunk_t Ni, const chunk_t Nr,
+				  size_t required_bytes);
+
+/*
+ * Old way ...
+ */
+
+struct pluto_crypto_req;
+
+void calc_dh_v2(struct pluto_crypto_req *r);
+
+#endif
diff -Naur libreswan-3.12-orig/programs/pluto/ikev2_prfplus.c libreswan-3.12/programs/pluto/ikev2_prfplus.c
--- libreswan-3.12-orig/programs/pluto/ikev2_prfplus.c	2014-11-06 22:52:50.000000000 -0500
+++ libreswan-3.12/programs/pluto/ikev2_prfplus.c	1969-12-31 19:00:00.000000000 -0500
@@ -1,106 +0,0 @@
-/*
- * Cryptographic helper function - calculate prf+() for ikev2
- *
- * Copyright (C) 2007 Michael C. Richardson <mcr@xelerance.com>
- * Copyright (C) 2010 Paul Wouters <paul@xelerance.com>
- * Copyright (C) 2013 D. Hugh Redelmeier <hugh@mimosa.com>
- *
- * 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.
- *
- * This code was developed with the support of Redhat corporation.
- *
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/types.h>
-#include <signal.h>
-
-#include <libreswan.h>
-
-#include "sysdep.h"
-#include "constants.h"
-#include "defs.h"
-#include "packet.h"
-#include "demux.h"
-#include "crypto.h"
-#include "rnd.h"
-#include "state.h"
-#include "pluto_crypt.h"
-#include "lswlog.h"
-#include "log.h"
-#include "timer.h"
-#include "ike_alg.h"
-#include "id.h"
-#include "secrets.h"
-#include "keys.h"
-#include "ikev2_prfplus.h"
-
-static void v2prfplus(struct v2prf_stuff *vps)
-{
-	struct hmac_ctx ctx;
-
-	hmac_init(&ctx, vps->prf_hasher, vps->skeyseed);
-	hmac_update_chunk(&ctx, vps->t);
-	hmac_update_chunk(&ctx, vps->ni);
-	hmac_update_chunk(&ctx, vps->nr);
-	hmac_update_chunk(&ctx, vps->spii);
-	hmac_update_chunk(&ctx, vps->spir);
-	hmac_update(&ctx, vps->counter, 1);
-	hmac_final_chunk(vps->t, "skeyseed_t1", &ctx);
-	DBG(DBG_CRYPT, {
-		    char b[20];
-		    snprintf(b, sizeof(b), "prf+[%u]:", vps->counter[0]);
-		    DBG_dump_chunk(b, vps->t);
-	    });
-
-	vps->counter[0]++;
-	vps->availbytes  = vps->t.len;
-	vps->nextbytes   = 0;
-}
-
-void v2genbytes(chunk_t *need,
-		unsigned int needed, const char *name,
-		struct v2prf_stuff *vps)
-{
-	u_char *target;
-
-	need->ptr = alloc_bytes(needed, name);
-	need->len = needed;
-	target = need->ptr;
-
-	while (needed > vps->availbytes) {
-		if (vps->availbytes) {
-			/* use any bytes which are presently in the buffer */
-			memcpy(target, &vps->t.ptr[vps->nextbytes],
-			       vps->availbytes);
-			target += vps->availbytes;
-			needed -= vps->availbytes;
-			vps->availbytes = 0;
-		}
-		/* generate more bits into t1 */
-		v2prfplus(vps);
-	}
-	passert(needed <= vps->availbytes);
-
-	memcpy(target, &vps->t.ptr[vps->nextbytes], needed);
-	vps->availbytes -= needed;
-	vps->nextbytes  += needed;
-}
-
diff -Naur libreswan-3.12-orig/programs/pluto/ikev2_prfplus.h libreswan-3.12/programs/pluto/ikev2_prfplus.h
--- libreswan-3.12-orig/programs/pluto/ikev2_prfplus.h	2014-11-06 22:52:50.000000000 -0500
+++ libreswan-3.12/programs/pluto/ikev2_prfplus.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,20 +0,0 @@
-#ifndef _IKEV2_PRF_H
-#define _IKEV2_PRF_H
-struct v2prf_stuff {
-	chunk_t t;
-	const struct hash_desc *prf_hasher;
-	PK11SymKey *skeyseed;
-	chunk_t ni;
-	chunk_t nr;
-	chunk_t spii;
-	chunk_t spir;
-	u_char counter[1]; /* why is this an array of 1? */
-	unsigned int availbytes;
-	unsigned int nextbytes;
-};
-
-extern void v2genbytes(chunk_t *need,
-		       unsigned int needed, const char *name,
-		       struct v2prf_stuff *vps);
-
-#endif
diff -Naur libreswan-3.12-orig/programs/pluto/ikev2_psk.c libreswan-3.12/programs/pluto/ikev2_psk.c
--- libreswan-3.12-orig/programs/pluto/ikev2_psk.c	2014-11-06 22:52:50.000000000 -0500
+++ libreswan-3.12/programs/pluto/ikev2_psk.c	2015-05-06 11:45:32.925301475 -0400
@@ -54,12 +54,14 @@
 #include "server.h"
 #include "vendor.h"
 #include "keys.h"
+#include "crypt_prf.h"
+#include "crypt_symkey.h"
 
 #include <nss.h>
 #include <pk11pub.h>
 
-static u_char psk_key_pad_str[] = "Key Pad for IKEv2";  /* 4306  2:15 */
-static int psk_key_pad_str_len = 17;                    /* sizeof( psk_key_pad_str); -1 */
+static const char psk_key_pad_str[] = "Key Pad for IKEv2";  /* 4306  2:15 */
+static const size_t psk_key_pad_str_len = 17;               /* sizeof( psk_key_pad_str); -1 */
 
 static bool ikev2_calculate_psk_sighash(struct state *st,
 					enum phase1_role role,
@@ -71,8 +73,7 @@
 	const char    *nonce_name;
 	const struct connection *c = st->st_connection;
 	const chunk_t *pss = get_preshared_secret(c);
-	unsigned int hash_len =  st->st_oakley.prf_hasher->hash_digest_len;
-	unsigned char prf_psk[hash_len];
+	const size_t hash_len =  st->st_oakley.prf_hasher->hash_digest_len;
 
 	if (pss == NULL) {
 		libreswan_log("No matching PSK found for connection:%s",
@@ -80,52 +81,25 @@
 		return FALSE; /* failure: no PSK to use */
 	}
 
-	CK_EXTRACT_PARAMS bs;
-	SECItem param;
-
 	/* RFC 4306 2.15:
 	 * AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>)
 	 */
 
 	/* calculate inner prf */
+	PK11SymKey *prf_psk;
 	{
-		struct hmac_ctx id_ctx;
-
-		PK11SymKey *tkey1 = pk11_derive_wrapper_lsw(st->st_shared_nss,
-							    CKM_CONCATENATE_DATA_AND_BASE, *pss, CKM_EXTRACT_KEY_FROM_KEY, CKA_DERIVE,
-							    0);
-		passert(tkey1 != NULL);
-
-		bs = 0;
-		param.data = (unsigned char*)&bs;
-		param.len = sizeof(bs);
-		PK11SymKey *tkey2 = PK11_Derive(tkey1,
-						CKM_EXTRACT_KEY_FROM_KEY,
-						&param,
-						CKM_CONCATENATE_BASE_AND_DATA,
-						CKA_DERIVE, pss->len);
-		passert(tkey2 != NULL);
-
-		hmac_init(&id_ctx, st->st_oakley.prf_hasher, tkey2);
-
-		PK11_FreeSymKey(tkey1);
-		PK11_FreeSymKey(tkey2);
-		hmac_update(&id_ctx, psk_key_pad_str, psk_key_pad_str_len);
-		hmac_final(prf_psk, &id_ctx);
+	struct crypt_prf *prf =
+		crypt_prf_init(("<prf-psk>"
+				" = prf(<psk>,\"Key Pad for IKEv2\")"),
+				st->st_oakley.prf_hasher,
+				st->st_shared_nss/*scratch*/);
+	crypt_prf_init_chunk("shared secret", prf, *pss);
+	crypt_prf_update(prf);
+	crypt_prf_update_bytes(psk_key_pad_str/*name*/, prf,
+				psk_key_pad_str, psk_key_pad_str_len);
+	prf_psk = crypt_prf_final(prf);
 	}
 
-	DBG(DBG_CRYPT,
-	    DBG_log("negotiated prf: %s hash length: %lu",
-		    st->st_oakley.prf_hasher->common.name,
-		    (long unsigned) hash_len));
-	DBG(DBG_PRIVATE,
-	    DBG_log("PSK , secret, used %s, length %lu",
-		    pss->ptr,  (long unsigned) pss->len);
-	    DBG_log("keypad used \"%s\", length %d", psk_key_pad_str,
-		    psk_key_pad_str_len));
-	DBG(DBG_CRYPT,
-	    DBG_dump("inner prf output", prf_psk, hash_len));
-
 	/* decide nonce based on the role */
 	if (role == O_INITIATOR) {
 		/* on initiator, we need to hash responders nonce */
@@ -138,52 +112,32 @@
 
 	/* calculate outer prf */
 	{
-		struct hmac_ctx id_ctx;
-		chunk_t pp_chunk;
-
-		pp_chunk.ptr = prf_psk;
-		pp_chunk.len = hash_len;
-
-		PK11SymKey *tkey1 = pk11_derive_wrapper_lsw(st->st_shared_nss,
-							    CKM_CONCATENATE_DATA_AND_BASE,
-							    pp_chunk,
-							    CKM_EXTRACT_KEY_FROM_KEY,
-							    CKA_DERIVE,
-							    0);
-		passert(tkey1 != NULL);
-
-		bs = 0;
-		param.data = (unsigned char*)&bs;
-		param.len = sizeof(bs);
-		PK11SymKey *tkey2 = PK11_Derive(tkey1,
-						CKM_EXTRACT_KEY_FROM_KEY,
-						&param,
-						CKM_CONCATENATE_BASE_AND_DATA,
-						CKA_DERIVE, hash_len);
-		passert(tkey2 != NULL);
-
-		hmac_init(&id_ctx, st->st_oakley.prf_hasher, tkey2);
-
-		PK11_FreeSymKey(tkey1);
-		PK11_FreeSymKey(tkey2);
-
-/*
- *  For the responder, the octets to
- *  be signed start with the first octet of the first SPI in the header
- *  of the second message and end with the last octet of the last payload
- *  in the second message.  Appended to this (for purposes of computing
- *  the signature) are the initiator's nonce Ni (just the value, not the
- *  payload containing it), and the value prf(SK_pr,IDr') where IDr' is
- *  the responder's ID payload excluding the fixed header.  Note that
- *  neither the nonce Ni nor the value prf(SK_pr,IDr') are transmitted.
- */
-
-		hmac_update(&id_ctx, firstpacket.ptr, firstpacket.len);
-		hmac_update(&id_ctx, nonce->ptr, nonce->len);
-		hmac_update(&id_ctx, idhash, hash_len);
-		hmac_final(signed_octets, &id_ctx);
-
+		struct crypt_prf *prf =
+			crypt_prf_init(("<signed-octets>"
+					" = prf(<prf-psk>, <msg octets>)"),
+				       st->st_oakley.prf_hasher,
+				       st->st_shared_nss /*scratch*/);
+		crypt_prf_init_symkey("<prf-psk>", prf, prf_psk);
+		/*
+		 * For the responder, the octets to be signed start
+		 * with the first octet of the first SPI in the header
+		 * of the second message and end with the last octet
+		 * of the last payload in the second message.
+		 * Appended to this (for purposes of computing the
+		 * signature) are the initiator's nonce Ni (just the
+		 * value, not the payload containing it), and the
+		 * value prf(SK_pr,IDr') where IDr' is the responder's
+		 * ID payload excluding the fixed header.  Note that
+		 * neither the nonce Ni nor the value prf(SK_pr,IDr')
+		 * are transmitted.
+		 */
+		crypt_prf_update(prf);
+		crypt_prf_update_chunk("first-packet", prf, firstpacket);
+		crypt_prf_update_chunk("nonce", prf, *nonce);
+		crypt_prf_update_bytes("hash", prf, idhash, hash_len);
+		crypt_prf_final_bytes(prf, signed_octets, hash_len);
 	}
+	free_any_symkey("<prf-psk>", &prf_psk);
 
 	DBG(DBG_CRYPT,
 	    DBG_dump_chunk("inputs to hash1 (first packet)", firstpacket);
diff -Naur libreswan-3.12-orig/programs/pluto/initiate.c libreswan-3.12/programs/pluto/initiate.c
--- libreswan-3.12-orig/programs/pluto/initiate.c	2014-11-06 22:52:50.000000000 -0500
+++ libreswan-3.12/programs/pluto/initiate.c	2015-05-06 11:45:32.925301475 -0400
@@ -132,7 +132,7 @@
 									c->name, c->interface->ip_dev->id_rname,
 									p->ip_dev->id_rname);
 							}
-							terminate_connection(c->name);
+							// terminate_connection(c->name);
 							c->interface = NULL; /* withdraw orientation */
 							return FALSE;
 						}
diff -Naur libreswan-3.12-orig/programs/pluto/log.c libreswan-3.12/programs/pluto/log.c
--- libreswan-3.12-orig/programs/pluto/log.c	2015-05-06 11:44:21.548466119 -0400
+++ libreswan-3.12/programs/pluto/log.c	2015-05-06 11:45:32.926301486 -0400
@@ -1208,7 +1208,7 @@
                                if (!st->st_ikev2) {
 					/* ikev1 takes integ from prf, ecept of cause gcm */
 					/* but we dont support gcm in ikev1 for now */
-					snprintf(integname, sizeof(integname), prfname);
+					jam_str(integname, sizeof(integname), prfname);
 				} else {
 					snprintf(integname, sizeof(integname), "none");
 			}
diff -Naur libreswan-3.12-orig/programs/pluto/Makefile libreswan-3.12/programs/pluto/Makefile
--- libreswan-3.12-orig/programs/pluto/Makefile	2015-05-06 11:44:21.590466613 -0400
+++ libreswan-3.12/programs/pluto/Makefile	2015-05-06 11:45:32.926301486 -0400
@@ -129,7 +129,8 @@
 	ikev1_dpd.c ikev1_dpd.h ikev1_spdb_struct.c \
 	ikev1_msgid.c \
         ikev2.c ikev2_parent.c ikev2_child.c ikev2_crypto.c \
-	ikev2_prfplus.c ikev2_spdb_struct.c \
+	crypt_symkey.c crypt_prf.c ikev1_prf.c ikev2_prf.c \
+	ikev2_spdb_struct.c \
 	ikev2_rsa.c ikev2_psk.c ikev2_x509.c \
 	kernel.c kernel.h \
 	${NETKEY_SRCS} \
@@ -176,7 +177,8 @@
 OBJSPLUTO += myid.o ipsec_doi.o
 OBJSPLUTO += ikev1.o ikev1_main.o ikev1_quick.o ikev1_dpd.o ikev1_spdb_struct.o ikev1_msgid.o
 OBJSPLUTO += ikev2.o ikev2_parent.o ikev2_child.o ikev2_spdb_struct.o 
-OBJSPLUTO += ikev2_rsa.o ikev2_psk.o ikev2_x509.o ikev2_crypto.o ikev2_prfplus.o
+OBJSPLUTO += ikev2_rsa.o ikev2_psk.o ikev2_x509.o ikev2_crypto.o
+OBJSPLUTO += crypt_symkey.o crypt_prf.o ikev1_prf.o ikev2_prf.o
 OBJSPLUTO += kernel.o
 OBJSPLUTO += $(NETKEY_OBJS) $(BSDKAME_OBJS) ${KLIPS_OBJS} ${MAST_OBJS} ${WIN2K_OBJS} ${PFKEYv2_OBJS}
 OBJSPLUTO += kernel_noklips.o rcv_whack.o
@@ -203,14 +205,16 @@
 OBJSWHACK = whack.o
 OBJSWHACKINIT = whackinit.o
 
+CAVP += cavp
+
 # we can't do tests with two conditions, but we can concatenate the strings
 SHOULDWERESTART=${USE_OBJDIR}$(wildcard plutomain.c)
 ifeq ($(SHOULDWERESTART),trueplutomain.c)
 all programs clean install:
 	cd ${LIBRESWANSRCDIR} && cd ${OBJDIRTOP}/programs/pluto && $(MAKE) $@
 else
-all: $(BINNAMEPLUTO) $(BINNAMEADNSIFNEEDED) $(BINNAMEWHACK) #$(BINNAMEWHACKINIT)
-programs: $(BINNAMEPLUTO) $(BINNAMEADNSIFNEEDED) $(BINNAMEWHACK) $(MANPAGES) #$(BINNAMEWHACKINIT) 
+all: $(BINNAMEPLUTO) $(BINNAMEADNSIFNEEDED) $(BINNAMEWHACK) $(CAVP) #$(BINNAMEWHACKINIT)
+programs: $(BINNAMEPLUTO) $(BINNAMEADNSIFNEEDED) $(BINNAMEWHACK) $(MANPAGES) $(CAVP) #$(BINNAMEWHACKINIT) 
 clean:	cleanall
 install: doinstall
 endif
@@ -290,6 +294,20 @@
 
 checkprograms:
 
+# Cryptographic Algorithm Validation Program (CAVP)
+# see: http://csrc.nist.gov/groups/STM/cavp/index.html
+CAVPSRC += cavp.c
+CAVPSRC += cavp_print.c
+CAVPSRC += cavp_stubs.c
+CAVPSRC += cavp_ikev1.c
+CAVPSRC += cavp_ikev2.c
+DISTSRC += $(CAVPSRC)
+OBJSCAVP = $(CAVPSRC:.c=.o) $(filter-out plutomain.o, $(OBJSPLUTO))
+cavp: $(OBJSCAVP)
+	$(CC) -o $@ $(OBJSCAVP) \
+		$(LDFLAGS) $(USERLINK) $(LIBSPLUTO) ${PLUTOMINUSL}
+
+
 .c.o:
 	$(CC) $(USERCOMPILE) ${PORTINCLUDE} $(COPTS) $(ALLFLAGS) -c $<
 
diff -Naur libreswan-3.12-orig/programs/pluto/pluto_constants.c libreswan-3.12/programs/pluto/pluto_constants.c
--- libreswan-3.12-orig/programs/pluto/pluto_constants.c	2015-05-06 11:44:21.549466131 -0400
+++ libreswan-3.12/programs/pluto/pluto_constants.c	2015-05-06 11:45:32.926301486 -0400
@@ -161,6 +161,9 @@
 /* story for state */
 
 const char *const state_story[] = {
+	"not defined and probably dead (internal)",             /* STATE_UNDEFINED */
+	"got an ACQUIRE message for this pair (internal)",      /* OPPO_QCQUIRE */
+	"got TXT specifying gateway (internal)",                /* OPPO_GW_DISCOVERED */
 	"expecting MI1",                                        /* STATE_MAIN_R0 */
 	"sent MI1, expecting MR1",                              /* STATE_MAIN_I1 */
 	"sent MR1, expecting MI2",                              /* STATE_MAIN_R1 */
@@ -206,7 +209,7 @@
 };
 
 enum_names state_stories =
-	{ STATE_MAIN_R0, STATE_IKEv2_ROOF - 1, state_story, NULL };
+	{ STATE_UNDEFINED, STATE_IKEv2_ROOF - 1, state_story, NULL };
 
 static const char *const natt_method_result_name[] = {
 };
diff -Naur libreswan-3.12-orig/programs/pluto/pluto_crypt.c libreswan-3.12/programs/pluto/pluto_crypt.c
--- libreswan-3.12-orig/programs/pluto/pluto_crypt.c	2014-11-06 22:52:50.000000000 -0500
+++ libreswan-3.12/programs/pluto/pluto_crypt.c	2015-05-06 11:45:32.927301498 -0400
@@ -63,6 +63,10 @@
 #include "lswconf.h"
 
 #include "lsw_select.h"
+#include "ikev2_prf.h"
+#include "crypt_dh.h"
+#include "ikev1_prf.h"
+
 
 TAILQ_HEAD(req_queue, pluto_crypto_req_cont);
 
diff -Naur libreswan-3.12-orig/programs/pluto/pluto_crypt.h libreswan-3.12/programs/pluto/pluto_crypt.h
--- libreswan-3.12-orig/programs/pluto/pluto_crypt.h	2015-05-06 11:44:21.570466378 -0400
+++ libreswan-3.12/programs/pluto/pluto_crypt.h	2015-05-06 11:45:32.927301498 -0400
@@ -382,10 +382,6 @@
 extern void finish_dh_v2(struct state *st,
 			 const struct pluto_crypto_req *r);
 
-extern void calc_dh_iv(struct pluto_crypto_req *r);
-extern void calc_dh(struct pluto_crypto_req *r);
-extern void calc_dh_v2(struct pluto_crypto_req *r);
-
 extern void unpack_KE_from_helper(
 	struct state *st,
 	const struct pluto_crypto_req *r,
diff -Naur libreswan-3.12-orig/programs/pluto/state.c libreswan-3.12/programs/pluto/state.c
--- libreswan-3.12-orig/programs/pluto/state.c	2015-05-06 11:44:21.571466389 -0400
+++ libreswan-3.12/programs/pluto/state.c	2015-05-06 11:45:32.928301510 -0400
@@ -65,6 +65,7 @@
 #include "md5.h"
 #include "cookie.h"
 #include "crypto.h" /* requires sha1.h and md5.h */
+#include "crypt_symkey.h"
 #include "spdb.h"
 
 #include <nss.h>
@@ -525,12 +526,7 @@
 	freeanychunk(st->st_nr);
 
 
-#    define free_any_nss_symkey(p)  { \
-		if ((p) != NULL) { \
-			PK11_FreeSymKey(p); \
-			(p) = NULL; \
-		} \
-	}
+#	define free_any_nss_symkey(p)  free_any_symkey(#p, &(p))
 	/* ??? free_any_nss_symkey(st->st_shared_nss); */
 	free_any_nss_symkey(st->st_skeyseed_nss);	/* same as st_skeyid_nss */
 	free_any_nss_symkey(st->st_skey_d_nss);	/* same as st_skeyid_d_nss */
@@ -1440,7 +1436,7 @@
 		 c->name, inst,
 		 st->st_remoteport,
 		 enum_name(&state_names, st->st_state),
-		 state_story[st->st_state - STATE_MAIN_R0],
+		 enum_name(&state_stories, st->st_state),
 		 st->st_event ? enum_name(&timer_event_names,
 					  st->st_event->ev_type) : "none",
 		 delta,
diff -Naur libreswan-3.12-orig/programs/pluto/test_buffer.c libreswan-3.12/programs/pluto/test_buffer.c
--- libreswan-3.12-orig/programs/pluto/test_buffer.c	2015-05-06 11:44:21.591466625 -0400
+++ libreswan-3.12/programs/pluto/test_buffer.c	2015-05-06 11:45:32.928301510 -0400
@@ -40,7 +40,7 @@
  * If this function fails, crash and burn.  Its been fed static data
  * so should never ever have a problem.
  */
-static chunk_t decode_hex_to_chunk(const char *original, const char *string)
+chunk_t decode_hex_to_chunk(const char *original, const char *string)
 {
 	/* The decoded buffer can't be bigger than the encoded string.  */
 	chunk_t chunk = zalloc_chunk(strlen(string), original);
@@ -154,8 +154,15 @@
 PK11SymKey *decode_to_key(CK_MECHANISM_TYPE cipher_mechanism,
 			  const char *encoded_key)
 {
-	PK11SlotInfo *slot = PK11_GetBestSlot(cipher_mechanism, NULL);
 	chunk_t raw_key = decode_to_chunk("key", encoded_key);
+	PK11SymKey *sym_key = chunk_to_key(cipher_mechanism, raw_key);
+	freeanychunk(raw_key);
+	return sym_key;
+}
+
+PK11SymKey *chunk_to_key(CK_MECHANISM_TYPE cipher_mechanism, chunk_t raw_key)
+{
+	PK11SlotInfo *slot = PK11_GetBestSlot(cipher_mechanism, NULL);
 	SECItem key_item;
 	key_item.type = siBuffer;
 	key_item.data = raw_key.ptr; /* ptr to an array of key bytes */
@@ -163,7 +170,6 @@
 	PK11SymKey *sym_key = PK11_ImportSymKey(slot, cipher_mechanism,
 						PK11_OriginUnwrap,
 						CKA_ENCRYPT, &key_item, NULL);
-	freeanychunk(raw_key);
 	PK11_FreeSlot(slot);
 	return sym_key;
 }
diff -Naur libreswan-3.12-orig/programs/pluto/test_buffer.h libreswan-3.12/programs/pluto/test_buffer.h
--- libreswan-3.12-orig/programs/pluto/test_buffer.h	2015-05-06 11:44:21.592466636 -0400
+++ libreswan-3.12/programs/pluto/test_buffer.h	2015-05-06 11:45:32.928301510 -0400
@@ -13,6 +13,7 @@
  * for more details.
  */
 
+chunk_t decode_hex_to_chunk(const char *original, const char *string);
 chunk_t decode_to_chunk(const char *prefix, const char *string);
 int compare_chunks(const char *prefix,
 		   chunk_t expected,
@@ -24,3 +25,5 @@
 		      size_t offset, size_t length);
 
 PK11SymKey *decode_to_key(CK_MECHANISM_TYPE cipher_mechanism, const char *string);
+
+PK11SymKey *chunk_to_key(CK_MECHANISM_TYPE cipher_mechanism, chunk_t raw_key);