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, ¶m, 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,
- ¶m,
- 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,
- ¶m,
- 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,
- ¶m,
- 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,
- ¶m,
- 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, ¶m,
- 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, ¶m, 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, ¶m, 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, ¶m,
- 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, ¶m1,
- 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, ¶m,
- 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, ¶m,
- 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, ¶m,
- 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,
- ¶m,
- CKM_EXTRACT_KEY_FROM_KEY,
- CKA_DERIVE, 0);
- passert(tkey39 != NULL);
-
- enc_key = PK11_DeriveWithFlags(tkey39,
- CKM_EXTRACT_KEY_FROM_KEY, ¶m1,
- 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,
- ¶m,
- 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,
- ¶m,
- 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,
- ¶m, 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,
- ¶m,
- 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,
- ¶m,
- CKM_EXTRACT_KEY_FROM_KEY,
- CKA_DERIVE,
- 0);
- passert(finalkey != NULL);
- } else {
- finalkey = PK11_Derive_lsw(finalkey,
- CKM_CONCATENATE_BASE_AND_KEY,
- ¶m,
- 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,
- ¶m1,
- 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,
- ¶m1,
- 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, ¶m, 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, ¶m, 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, ¶m,
+ 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, ¶m, 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, ¶m, 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,
- ¶m,
- 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,
- ¶m,
- 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);