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 + * + * 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 . + * + * 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 +/* #include */ +#include +#include + +#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); + /* "[" [ " = " ] "]" */ + *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 ] |-\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 + * + * 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 . + * + * 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 + * + * 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 . + * + * 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 + +#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 + * + * 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 . + * + * 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 + * + * 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 . + * + * 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 + +#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 + * + * 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 . + * + * 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 + * + * 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 . + * + * 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 +#include + +#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 + * + * 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 . + * + * 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 + +#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 #include #include #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 + * Copyright (C) 2008 Antony Antony + * Copyright (C) 2009 David McCullough + * Copyright (C) 2009-2012 Avesh Agarwal + * Copyright (C) 2009-2010 Paul Wouters + * Copyright (C) 2010 Tuomo Soini + * Copyright (C) 2012-2013 Paul Wouters + * Copyright (C) 2012 Wes Hardaker + * Copyright (C) 2013 Antony Antony + * Copyright (C) 2013 D. Hugh Redelmeier + * Copyright (C) 2015 Paul Wouters + * Copyright (C) 2015 Andrew Cagney + * + * 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 . + * + * 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 +#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 + * Copyright (C) 2008 Antony Antony + * Copyright (C) 2009 David McCullough + * Copyright (C) 2009-2012 Avesh Agarwal + * Copyright (C) 2009-2010 Paul Wouters + * Copyright (C) 2010 Tuomo Soini + * Copyright (C) 2012-2013 Paul Wouters + * Copyright (C) 2012 Wes Hardaker + * Copyright (C) 2013 Antony Antony + * Copyright (C) 2013 D. Hugh Redelmeier + * Copyright (C) 2015 Paul Wouters + * Copyright (C) 2015 Andrew Cagney + * + * 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 . + * + * 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 + +//#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 + * Copyright (C) 2010 Paul Wouters + * Copyright (C) 2013 D. Hugh Redelmeier + * Copyright (C) 2015 Andrew Cagney + * + * 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 . + * + * 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 + +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 + * + * 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 . + * + * 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 + * + * 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 . + * + * 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 +#include +#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 * Copyright (C) 2010-2012 Avesh Agarwal * Copyright (C) 2012 Paul Wouters - * Copyright (C) 2012-2013 Paul Wouters + * Copyright (C) 2012-2015 Paul Wouters * Copyright (C) 2013 D. Hugh Redelmeier + * Copyright (C) 2015, Andrew Cagney * * 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 #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 + * Copyright (C) 2010 Paul Wouters + * Copyright (C) 2013 D. Hugh Redelmeier + * Copyright (C) 2015 Andrew Cagney + * + * 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 . + * + * 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 +#include + +#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 + * Copyright (C) 2010 Paul Wouters + * Copyright (C) 2013 D. Hugh Redelmeier + * Copyright (C) 2015 Andrew Cagney + * + * 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 . + * + * 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 + * Copyright (C) 2010 Paul Wouters + * Copyright (C) 2013 D. Hugh Redelmeier + * Copyright (C) 2015 Andrew Cagney + * + * 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 . + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 + * Copyright (C) 2010 Paul Wouters + * Copyright (C) 2013 D. Hugh Redelmeier + * Copyright (C) 2015 Andrew Cagney + * + * 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 . + * + * 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 - * Copyright (C) 2010 Paul Wouters - * Copyright (C) 2013 D. Hugh Redelmeier - * - * 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 . - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#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 #include -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"), ) */ /* 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(,\"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(("" + " = prf(, )"), + st->st_oakley.prf_hasher, + st->st_shared_nss /*scratch*/); + crypt_prf_init_symkey("", 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); 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 @@ -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);