diff -Naur libreswan-3.27-orig/include/alg_byname.h libreswan-3.27/include/alg_byname.h --- libreswan-3.27-orig/include/alg_byname.h 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/include/alg_byname.h 2019-02-15 16:32:28.971835267 -0500 @@ -30,26 +30,26 @@ * messages better align with the input files. */ -bool alg_byname_ok(const struct proposal_parser *parser, +bool alg_byname_ok(struct proposal_parser *parser, const struct ike_alg *alg, shunk_t print_name); /* * Helper functions to implement most of the lookup. */ -const struct ike_alg *encrypt_alg_byname(const struct proposal_parser *parser, +const struct ike_alg *encrypt_alg_byname(struct proposal_parser *parser, shunk_t name, size_t key_bit_length, shunk_t print_name); -const struct ike_alg *prf_alg_byname(const struct proposal_parser *parser, +const struct ike_alg *prf_alg_byname(struct proposal_parser *parser, shunk_t name, size_t key_bit_length, shunk_t print_name); -const struct ike_alg *integ_alg_byname(const struct proposal_parser *parser, +const struct ike_alg *integ_alg_byname(struct proposal_parser *parser, shunk_t name, size_t key_bit_length, shunk_t print_name); -const struct ike_alg *dh_alg_byname(const struct proposal_parser *parser, +const struct ike_alg *dh_alg_byname(struct proposal_parser *parser, shunk_t name, size_t key_bit_length, shunk_t print_name); diff -Naur libreswan-3.27-orig/include/alg_info.h libreswan-3.27/include/alg_info.h --- libreswan-3.27-orig/include/alg_info.h 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/include/alg_info.h 1969-12-31 19:00:00.000000000 -0500 @@ -1,245 +0,0 @@ -/* Algorithm info parsing and creation functions - * - * Author: JuanJo Ciarlante - * Copyright (C) 2007 Michael Richardson - * Copyright (C) 2012-2013 Paul Wouters - * Copyright (C) 2013 D. Hugh Redelmeier - * Copyright (C) 2013 Paul Wouters - * Copyright (C) 2015-2017 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 ALG_INFO_H -#define ALG_INFO_H - -#include "lswcdefs.h" -#include "constants.h" -#include "ike_alg.h" -#include "shunk.h" - -struct alg_info; -struct proposal_protocol; -struct proposal_info; -struct proposal_policy; -struct proposal_parser; - -typedef const struct ike_alg *(alg_byname_fn)(const struct proposal_parser *parser, - shunk_t name, size_t key_bit_length, - shunk_t print_name); - -/* - * Parameters to tune the parser. - */ - -struct proposal_policy { - bool ikev1; - bool ikev2; - bool pfs; /* For CHILD SA, use DH from IKE SA */ - /* - * According to current policy, is the algorithm ok - * (supported)? If it isn't return FALSE. - * - * For instance, an IKE algorithm requires in-process support; - * while an ESP/AH algorithm requires kernel support. - */ - bool (*alg_is_ok)(const struct ike_alg *alg); - /* - * Print a warning. Signature needs to match libreswan_log. - */ - int (*warning)(const char *fmt, ...) PRINTF_LIKE(1); -}; - -/* - * Defaults to fill in. - */ - -struct proposal_defaults { - const struct ike_alg **dh; - const struct ike_alg **prf; - const struct ike_alg **integ; - const struct ike_alg **encrypt; -}; - -/* - * Parameters to set the parser's basic behaviour - ESP/AH/IKE. - */ - -struct proposal_protocol { - const char *name; - enum ike_alg_key ikev1_alg_id; - - /* - * Lists of defaults. - */ - const struct proposal_defaults *ikev1_defaults; - const struct proposal_defaults *ikev2_defaults; - - /* - * Is the proposal OK? - * - * This is the final check, if this succeeds then the proposal - * is added. - */ - bool (*proposal_ok)(const struct proposal_parser *parser, - const struct proposal_info *proposal); - - /* - * XXX: Is the proto-id needed? Parser should be protocol - * agnostic. - */ - unsigned protoid; - - /* - * This lookup functions must set err and return null if NAME - * isn't valid. - */ - alg_byname_fn *encrypt_alg_byname; - alg_byname_fn *prf_alg_byname; - alg_byname_fn *integ_alg_byname; - alg_byname_fn *dh_alg_byname; -}; - -/* - * Everything combined. - */ -struct proposal_parser { - const struct proposal_protocol *protocol; - const struct proposal_param *param; - const struct proposal_policy *policy; - char *err_buf; - size_t err_buf_len; -}; - -/* - * A proposal as decoded by the parser. - */ - -struct proposal_info { - /* - * The encryption algorithm and key length. - * - * Because struct encrypt_desc still specifies multiple key - * lengths, ENCKEYLEN is still required. - */ - const struct encrypt_desc *encrypt; - size_t enckeylen; /* keylength for ESP transform (bits) */ - /* - * The integrity and PRF algorithms. - */ - const struct prf_desc *prf; - const struct integ_desc *integ; - /* - * PFS/DH negotiation. - */ - const struct oakley_group_desc *dh; - /* - * Which protocol is this proposal intended for? - */ - const struct proposal_protocol *protocol; -}; - -/* common prefix of struct alg_info_esp and struct alg_info_ike */ -struct alg_info { - int alg_info_cnt; - int ref_cnt; - struct proposal_info proposals[128]; -}; - -struct alg_info_esp { - struct alg_info ai; /* common prefix */ -}; - -struct alg_info_ike { - struct alg_info ai; /* common prefix */ -}; - -extern void alg_info_free(struct alg_info *alg_info); -extern void alg_info_addref(struct alg_info *alg_info); -extern void alg_info_delref(struct alg_info *alg_info); - -extern struct alg_info_ike *alg_info_ike_create_from_str(const struct proposal_policy *policy, - const char *alg_str, - char *err_buf, size_t err_buf_len); - -extern struct alg_info_esp *alg_info_esp_create_from_str(const struct proposal_policy *policy, - const char *alg_str, - char *err_buf, size_t err_buf_len); - -extern struct alg_info_esp *alg_info_ah_create_from_str(const struct proposal_policy *policy, - const char *alg_str, - char *err_buf, size_t err_buf_len); - -size_t lswlog_proposal_info(struct lswlog *log, const struct proposal_info *proposal); -size_t lswlog_alg_info(struct lswlog *log, const struct alg_info *alg_info); - -/* - * Iterate through the elements of an ESP or IKE table. - * - * Use __typeof__ instead of const to get around ALG_INFO some times - * being const and sometimes not. - * - * XXX: yes, they are the same! - */ - -#define FOR_EACH_PROPOSAL_INFO(ALG_INFO, PROPOSAL_INFO) \ - for (__typeof__((ALG_INFO)->proposals[0]) *(PROPOSAL_INFO) = (ALG_INFO)->proposals; \ - (PROPOSAL_INFO) < (ALG_INFO)->proposals + (ALG_INFO)->alg_info_cnt; \ - (PROPOSAL_INFO)++) - -#define FOR_EACH_ESP_INFO(ALG_INFO, ESP_INFO) \ - FOR_EACH_PROPOSAL_INFO(&((ALG_INFO)->ai), ESP_INFO) - -#define FOR_EACH_IKE_INFO(ALG_INFO, IKE_INFO) \ - FOR_EACH_PROPOSAL_INFO(&((ALG_INFO)->ai), IKE_INFO) - -/* - * Error indicated by err_buf[0] != '\0'. - * - * POLICY should be used to guard algorithm supported checks. For - * instance: if POLICY=IKEV1, then IKEv1 support is required (IKEv2 is - * don't care); and if POLICY=IKEV1|IKEV2, then both IKEv1 and IKEv2 - * support is required. - * - * Parsing with POLICY=IKEV1, but then proposing the result using - * IKEv2 is a program error. The IKEv2 should complain loudly and, - * we hope, not crash. - * - * Parsing with POLICY='0' is allowed. It will accept the algorithms - * unconditionally (spi.c seems to need this). - */ - -struct proposal_parser proposal_parser(const struct proposal_policy *policy, - const struct proposal_protocol *protocol, - char *err_buf, size_t err_buf_len); - -bool alg_info_parse_str(const struct proposal_parser *parser, - struct alg_info *alg_info, - shunk_t alg_str); - -/* - * Check that encrypt==AEAD and/or integ==none don't contradict. - */ -bool proposal_aead_none_ok(const struct proposal_parser *parser, - const struct proposal_info *proposal); - -bool alg_info_pfs_vs_dh_check(const struct proposal_parser *parser, - struct alg_info_esp *aie); - -#if 0 -/* return true if it really is an error (when impaired return false) */ -bool proposal_error(const struct proposal_parser *parser, - const char *message, ...) PRINTF_LIKE(2); -#endif - -bool impair_proposal_errors(const struct proposal_parser *parser); - -#endif /* ALG_INFO_H */ diff -Naur libreswan-3.27-orig/include/ike_alg.h libreswan-3.27/include/ike_alg.h --- libreswan-3.27-orig/include/ike_alg.h 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/include/ike_alg.h 2019-02-15 16:32:28.972835277 -0500 @@ -252,7 +252,7 @@ * Easier to just require that this contain everything then * poke around in multiple places. */ - const char *names[5]; + const char *names[6]; /* * See above. * diff -Naur libreswan-3.27-orig/include/lswlog.h libreswan-3.27/include/lswlog.h --- libreswan-3.27-orig/include/lswlog.h 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/include/lswlog.h 2019-02-15 16:32:28.973835286 -0500 @@ -577,7 +577,7 @@ #define PEXPECT_LOG(FMT, ...) \ libreswan_pexpect_log(__func__, \ PASSERT_BASENAME, __LINE__, \ - FMT, __VA_ARGS__) + FMT,##__VA_ARGS__) /* diff -Naur libreswan-3.27-orig/include/names_constant.h libreswan-3.27/include/names_constant.h --- libreswan-3.27-orig/include/names_constant.h 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/include/names_constant.h 2019-02-15 16:32:28.973835286 -0500 @@ -41,6 +41,8 @@ extern enum_names auth_alg_names; extern enum_names oakley_lifetime_names; +extern enum_names ike_version_names; +extern enum_names ike_version_liveness_names; extern enum_names version_names; extern enum_names doi_names; extern enum_names ikev1_payload_names; diff -Naur libreswan-3.27-orig/include/pluto_constants.h libreswan-3.27/include/pluto_constants.h --- libreswan-3.27-orig/include/pluto_constants.h 2019-02-15 16:31:43.034408076 -0500 +++ libreswan-3.27/include/pluto_constants.h 2019-02-15 16:32:28.974835295 -0500 @@ -28,6 +28,12 @@ # define DEFAULT_DNSSEC_ROOTKEY_FILE "" # endif +enum ike_version { + IKEv1 = 1, + IKEv2 = 2, +#define IKE_VERSION_ROOF 3 +}; + /* * IETF has no recommendations * FIPS SP800-77 sayas IKE max is 24h, IPsec max is 8h diff -Naur libreswan-3.27-orig/include/proposals.h libreswan-3.27/include/proposals.h --- libreswan-3.27-orig/include/proposals.h 1969-12-31 19:00:00.000000000 -0500 +++ libreswan-3.27/include/proposals.h 2019-02-15 16:32:28.975835304 -0500 @@ -0,0 +1,264 @@ +/* Proposals, for libreswan + * + * Author: JuanJo Ciarlante + * Copyright (C) 2007 Michael Richardson + * Copyright (C) 2012-2013 Paul Wouters + * Copyright (C) 2013 D. Hugh Redelmeier + * Copyright (C) 2013 Paul Wouters + * Copyright (C) 2015-2019 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 PROPOSALS_H +#define PROPOSALS_H + +#include "lswcdefs.h" +#include "constants.h" +#include "ike_alg.h" +#include "shunk.h" + +struct alg_info; +struct proposal_protocol; +struct proposal; +struct proposals; +struct proposal_policy; +struct proposal_parser; + +/* + * XXX: needs to be merged with IKE_ALG_TYPE. + */ +enum proposal_algorithm { + PROPOSAL_encrypt, + PROPOSAL_prf, + PROPOSAL_integ, + PROPOSAL_dh, + PROPOSAL_ALGORITHM_ROOF, +}; + +/* + * Everything combined. + */ +struct proposal_parser { + const struct proposal_protocol *protocol; + const struct proposal_param *param; + const struct proposal_policy *policy; + /* need to eliminate hardwired size */ + char error[200]; +}; + +/* + * Parameters to tune the parser. + */ + +struct proposal_policy { + enum ike_version version; + unsigned parser_version; + bool pfs; /* For CHILD SA, use DH from IKE SA */ + bool check_pfs_vs_dh; + /* + * According to current policy, is the algorithm ok + * (supported)? If it isn't return FALSE. + * + * For instance, an IKE algorithm requires in-process support; + * while an ESP/AH algorithm requires kernel support. + */ + bool (*alg_is_ok)(const struct ike_alg *alg); + /* + * Print a warning. Signature needs to match libreswan_log. + */ + int (*warning)(const char *fmt, ...) PRINTF_LIKE(1); +}; + +/* + * Defaults the parser uses to fill things in. + */ + +struct proposal_defaults { + const struct ike_alg **dh; + const struct ike_alg **prf; + const struct ike_alg **integ; + const struct ike_alg **encrypt; +}; + +/* + * The protocol - ESP/AH/IKE - the parser is processing. + */ + +typedef const struct ike_alg *(alg_byname_fn)(struct proposal_parser *parser, + shunk_t name, size_t key_bit_length, + shunk_t print_name); + +struct proposal_protocol { + const char *name; + enum ike_alg_key ikev1_alg_id; + + /* + * Lists of defaults for each IKE version. + */ + const struct proposal_defaults *defaults[IKE_VERSION_ROOF]; + + /* + * Is the proposal OK? + * + * This is the final check, if this succeeds then the proposal + * is added. + */ + bool (*proposal_ok)(struct proposal_parser *parser, + const struct proposal *proposal); + + /* + * XXX: Is the proto-id needed? Parser should be protocol + * agnostic. + */ + unsigned protoid; + + /* + * This lookup functions must set err and return null if NAME + * isn't valid. + */ + alg_byname_fn *encrypt_alg_byname; + alg_byname_fn *prf_alg_byname; + alg_byname_fn *integ_alg_byname; + alg_byname_fn *dh_alg_byname; +}; + +/* + * A proposal as decoded by the parser. + */ + +struct algorithm { + const struct ike_alg *desc; + /* + * Because struct encrypt_desc still specifies multiple key + * lengths, ENCKEYLEN is still required. + */ + int enckeylen; /* only one! */ + struct algorithm *next; +}; + +/* return counts of encrypt=aead and integ=none */ +bool proposal_encrypt_aead(const struct proposal *proposal); +bool proposal_encrypt_norm(const struct proposal *proposal); +bool proposal_integ_none(const struct proposal *proposal); + +unsigned nr_proposals(struct proposals *proposals); + +extern void proposals_addref(struct proposals **proposals); +extern void proposals_delref(struct proposals **proposals); + +extern struct proposal *alloc_proposal(struct proposal_parser *parser); +extern void free_proposal(struct proposal **proposal); + +void free_algorithms(struct proposal *proposal, enum proposal_algorithm algorithm); +void append_proposal(struct proposals *proposals, struct proposal **proposal); +void append_algorithm(struct proposal_parser *parser, + struct proposal *proposal, enum proposal_algorithm algorithm, + const struct ike_alg *alg, int enckeylen); + +struct proposal_parser *alloc_proposal_parser(const struct proposal_policy *policy, + const struct proposal_protocol *protocol); +void free_proposal_parser(struct proposal_parser **parser); +struct proposal_parser *ike_proposal_parser(const struct proposal_policy *policy); +struct proposal_parser *esp_proposal_parser(const struct proposal_policy *policy); +struct proposal_parser *ah_proposal_parser(const struct proposal_policy *policy); + +/* + * XXX: useful? + */ +struct ike_proposals { + struct proposals *p; +}; + +struct child_proposals { + struct proposals *p; +}; + +void fmt_proposal(struct lswlog *log, + const struct proposal *proposal); +void fmt_proposals(struct lswlog *log, const struct proposals *proposals); + +/* + * Iterate through all the proposals and the proposal's algorithms. + * + * Use __typeof__ instead of const to get around ALG_INFO some times + * being const and sometimes not. + */ + +struct proposal *next_proposal(const struct proposals *proposals, + struct proposal *last_proposal); + +#define FOR_EACH_PROPOSAL(PROPOSALS, PROPOSAL) \ + for (struct proposal *PROPOSAL = next_proposal(PROPOSALS, NULL); \ + PROPOSAL != NULL; \ + PROPOSAL = next_proposal(PROPOSALS, PROPOSAL)) + +struct algorithm *next_algorithm(const struct proposal *proposal, + enum proposal_algorithm algorithm, + struct algorithm *last); + +#define FOR_EACH_ALGORITHM(PROPOSAL, TYPE, ALGORITHM) \ + for (struct algorithm *ALGORITHM = next_algorithm(PROPOSAL, PROPOSAL_##TYPE, NULL); \ + ALGORITHM != NULL; ALGORITHM = next_algorithm(PROPOSAL, PROPOSAL_##TYPE, ALGORITHM)) + +/* + * Error indicated by err_buf[0] != '\0'. + * + * POLICY should be used to guard algorithm supported checks. For + * instance: if POLICY=IKEV1, then IKEv1 support is required (IKEv2 is + * don't care); and if POLICY=IKEV1|IKEV2, then both IKEv1 and IKEv2 + * support is required. + * + * Parsing with POLICY=IKEV1, but then proposing the result using + * IKEv2 is a program error. The IKEv2 should complain loudly and, + * we hope, not crash. + * + * Parsing with POLICY='0' is allowed. It will accept the algorithms + * unconditionally (spi.c seems to need this). + */ + +struct proposals *proposals_from_str(struct proposal_parser *parser, + const char *str); + +bool v1_proposals_parse_str(struct proposal_parser *parser, + struct proposals *proposals, + shunk_t alg_str); +bool v2_proposals_parse_str(struct proposal_parser *parser, + struct proposals *proposals, + shunk_t alg_str); + +/* + * Check that encrypt==AEAD and/or integ==none don't contradict. + */ +bool proposal_aead_none_ok(struct proposal_parser *parser, + const struct proposal *proposal); + +void proposal_error(struct proposal_parser *parser, + const char *message, ...) PRINTF_LIKE(2); + +bool impair_proposal_errors(struct proposal_parser *parser); + +/* + * Convert a generic proposal back into something the IKEv1 code can + * digest. + */ +struct v1_proposal { + int enckeylen; + const struct encrypt_desc *encrypt; + const struct prf_desc *prf; + const struct integ_desc *integ; + const struct oakley_group_desc *dh; + const struct proposal_protocol *protocol; +}; + +struct v1_proposal v1_proposal(const struct proposal *proposal); + +#endif /* PROPOSALS_H */ diff -Naur libreswan-3.27-orig/include/shunk.h libreswan-3.27/include/shunk.h --- libreswan-3.27-orig/include/shunk.h 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/include/shunk.h 2019-02-15 16:32:28.975835304 -0500 @@ -1,7 +1,6 @@ -/* - * string fragments, for libreswan +/* constant string (octet) fragments, for libreswan * - * Copyright (C) 2018 Andrew Cagney + * Copyright (C) 2018-2019 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 @@ -21,8 +20,15 @@ #include /* size_t */ /* - * shunk_t is a rip of of chunk_t, but with a character pointer. It - * is intended for string slicing. + * Think of shunk_t and shunk_t as opposite solutions to the same + * problem - carving up streams of octets: + * + * shunk_t's buffer is constant making it good for manipulating static + * constant data (such as "a string"), chunk_t's is not. + * + * shunk_t's buffer is of type 'char' (which may or may not be signed) + * making it easier to manipulate strings, chunk_t's is uint8_t making + * it easier to manipulate raw bytes. */ struct shunk { @@ -32,21 +38,49 @@ typedef struct shunk shunk_t; -extern const shunk_t empty_shunk; +/* + * Just like for strings, an empty or zero length shunk such as + * {.ptr="",.len = 0} should not be confused with the NULL shunk + * (i.e., {.ptr=NULL,.len=0}). + * + * Use 'null_shunk' in initialisers. The only exception is static + * initializers - which will get a compiler error - and NULL_SHUNK can + * be used. + */ + +#define NULL_SHUNK { .ptr = NULL, .len = 0, } +extern const shunk_t null_shunk; shunk_t shunk1(const char *ptr); /* strlen() implied */ shunk_t shunk2(const char *ptr, int len); /* - * shunk version of strsep() (which is like strtok()) + * A shunk version of strsep() (which is like strtok()) - split INPUT + * in two using a character from the DELIM set. + * + * If INPUT contains a character from the DELIM set, return the + * characters before the DELIM character as the next TOKEN, and set + * INPUT to the sub-string following the DELIM character. + * + * If INPUT contains no character from the DELIM set, return INPUT as + * the next TOKEN (possibly empty), and set INPUT to the null_shunk. + * + * If INPUT is the null_shunk, return the null_shunk as the next + * TOKEN, string remains unchanged (still the null_shunk). + * + * One way to implement a simple parser is to use TOKEN.ptr==NULL as + * an end-of-input indicator: * - * Split SHUNK in two using the DELIM set. Return a shunk of the - * characters up to but not including DELIM (or the entire string if - * DELIM isn't found. Update SHUNK to be one past DELIM. + * shunk_t token = shunk_strsep(&input, ","); + * while (token.ptr != NULL) { + * ... process token ... + * token = shunk_strsep(&input, ","); + * } * - * XXX: should this return the DELIM? + * XXX: Provided INPUT.ptr is non-NULL, INPUT.ptr[-1] is the DELIM + * character; should this be made an explict parameter. */ -shunk_t shunk_strsep(shunk_t *shunk, const char *delim); +shunk_t shunk_strsep(shunk_t *input, const char *delim); /* * shunk version of string compare functions (or at least libreswan's diff -Naur libreswan-3.27-orig/lib/libswan/ah_info.c libreswan-3.27/lib/libswan/ah_info.c --- libreswan-3.27-orig/lib/libswan/ah_info.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/lib/libswan/ah_info.c 2019-02-15 16:50:12.776728076 -0500 @@ -22,50 +22,71 @@ #include "lswalloc.h" #include "lswlog.h" -#include "alg_info.h" +#include "proposals.h" #include "alg_byname.h" #include "lswfips.h" #include "ike_alg.h" #include "ike_alg_integ.h" -static bool ah_proposal_ok(const struct proposal_parser *parser, - const struct proposal_info *proposal) +static bool ah_proposal_ok(struct proposal_parser *parser, + const struct proposal *proposal) { - impaired_passert(PROPOSAL_PARSER, proposal->encrypt == NULL); - impaired_passert(PROPOSAL_PARSER, proposal->prf == NULL); - impaired_passert(PROPOSAL_PARSER, proposal->integ != NULL); + impaired_passert(PROPOSAL_PARSER, + next_algorithm(proposal, PROPOSAL_encrypt, NULL) == NULL); + impaired_passert(PROPOSAL_PARSER, + next_algorithm(proposal, PROPOSAL_prf, NULL) == NULL); + impaired_passert(PROPOSAL_PARSER, + next_algorithm(proposal, PROPOSAL_integ, NULL) != NULL); /* ah=null is invalid */ - if (!IMPAIR(ALLOW_NULL_NONE) && - proposal->integ == &ike_alg_integ_none) { - snprintf(parser->err_buf, parser->err_buf_len, - "AH cannot have 'none' as the integrity algorithm"); - if (!impair_proposal_errors(parser)) { - return false; + if (!IMPAIR(ALLOW_NULL_NONE)) { + FOR_EACH_ALGORITHM(proposal, integ, alg) { + /* passerts */ + const struct integ_desc *integ = integ_desc(alg->desc); + if (integ == &ike_alg_integ_none) { + proposal_error(parser, "AH cannot have 'none' as the integrity algorithm"); + if (!impair_proposal_errors(parser)) { + return false; + } + } } } return true; } -static const struct ike_alg *default_ah_integ[] = { +static const struct ike_alg *default_v1_ah_integ[] = { #ifdef USE_SHA1 &ike_alg_integ_sha1.common, #endif NULL, }; -const struct proposal_defaults ah_defaults = { - .integ = default_ah_integ, +static const struct ike_alg *default_v2_ah_integ[] = { +#ifdef USE_SHA2 + &ike_alg_integ_sha2_512.common, + &ike_alg_integ_sha2_256.common, +#endif + NULL, +}; + +const struct proposal_defaults v1_ah_defaults = { + .integ = default_v1_ah_integ, +}; + +const struct proposal_defaults v2_ah_defaults = { + .integ = default_v2_ah_integ, }; const struct proposal_protocol ah_proposal_protocol = { .name = "AH", .ikev1_alg_id = IKEv1_ESP_ID, .protoid = PROTO_IPSEC_AH, - .ikev1_defaults = &ah_defaults, - .ikev2_defaults = &ah_defaults, + .defaults = { + [IKEv1] = &v1_ah_defaults, + [IKEv2] = &v2_ah_defaults, + }, .proposal_ok = ah_proposal_ok, .integ_alg_byname = integ_alg_byname, .dh_alg_byname = dh_alg_byname, @@ -77,7 +98,7 @@ * parser configuration - encryption isn't allowed. * * ??? the only difference between - * alg_info_ah_create_from_str and alg_info_esp_create_from_str + * ah_proposals_create_from_str and alg_info_esp_create_from_str * is in the second argument to proposal_parser. * * XXX: On the other hand, since "struct ike_info" and "struct @@ -87,33 +108,7 @@ /* This function is tested in testing/algparse/algparse.c */ -struct alg_info_esp *alg_info_ah_create_from_str(const struct proposal_policy *policy, - const char *alg_str, - char *err_buf, size_t err_buf_len) +struct proposal_parser *ah_proposal_parser(const struct proposal_policy *policy) { - shunk_t string = shunk1(alg_str); - const struct proposal_parser parser = proposal_parser(policy, - &ah_proposal_protocol, - err_buf, err_buf_len); - - /* - * alg_info storage should be sized dynamically - * but this may require two passes to know - * transform count in advance. - */ - struct alg_info_esp *alg_info_ah = alloc_thing(struct alg_info_esp, "alg_info_ah"); - - if (!alg_info_parse_str(&parser, &alg_info_ah->ai, string)) { - passert(err_buf[0] != '\0'); - alg_info_free(&alg_info_ah->ai); - return NULL; - } - - if (!alg_info_pfs_vs_dh_check(&parser, alg_info_ah)) { - passert(err_buf[0] != '\0'); - alg_info_free(&alg_info_ah->ai); - return NULL; - } - - return alg_info_ah; + return alloc_proposal_parser(policy, &ah_proposal_protocol); } diff -Naur libreswan-3.27-orig/lib/libswan/alg_byname.c libreswan-3.27/lib/libswan/alg_byname.c --- libreswan-3.27-orig/lib/libswan/alg_byname.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/lib/libswan/alg_byname.c 2019-02-15 16:32:28.976835314 -0500 @@ -17,11 +17,11 @@ #include #include "lswlog.h" -#include "alg_info.h" +#include "proposals.h" #include "alg_byname.h" #include "ike_alg.h" -bool alg_byname_ok(const struct proposal_parser *parser, +bool alg_byname_ok(struct proposal_parser *parser, const struct ike_alg *alg, shunk_t print_name) { const struct proposal_protocol *protocol = parser->protocol; @@ -30,19 +30,27 @@ * If the connection is IKEv1|IKEv2 then this code will * exclude anything not supported by both protocols. */ - if (policy->ikev1 && alg->id[protocol->ikev1_alg_id] < 0) { - snprintf(parser->err_buf, parser->err_buf_len, - "%s %s algorithm '"PRI_SHUNK"' is not supported by IKEv1", - protocol->name, ike_alg_type_name(alg->algo_type), - PRI_shunk(print_name)); - return false; - } - if (policy->ikev2 && alg->id[IKEv2_ALG_ID] < 0) { - snprintf(parser->err_buf, parser->err_buf_len, - "%s %s algorithm '"PRI_SHUNK"' is not supported by IKEv2", - protocol->name, ike_alg_type_name(alg->algo_type), - PRI_shunk(print_name)); - return false; + switch (policy->version) { + case IKEv1: + /* IKEv1 has different IDs for ESP/IKE/AH */ + if (alg->id[protocol->ikev1_alg_id] < 0) { + proposal_error(parser, "%s %s algorithm '"PRI_SHUNK"' is not supported by IKEv1", + protocol->name, ike_alg_type_name(alg->algo_type), + PRI_shunk(print_name)); + return false; + } + break; + case IKEv2: + if (alg->id[IKEv2_ALG_ID] < 0) { + proposal_error(parser, "%s %s algorithm '"PRI_SHUNK"' is not supported by IKEv2", + protocol->name, ike_alg_type_name(alg->algo_type), + PRI_shunk(print_name)); + return false; + } + break; + default: + /* ignore */ + break; } /* * According to parser policy, is the algorithm "implemented"? @@ -54,10 +62,9 @@ */ passert(policy->alg_is_ok != NULL); if (!policy->alg_is_ok(alg)) { - snprintf(parser->err_buf, parser->err_buf_len, - "%s %s algorithm '"PRI_SHUNK"' is not supported", - protocol->name, ike_alg_type_name(alg->algo_type), - PRI_shunk(print_name)); + proposal_error(parser, "%s %s algorithm '"PRI_SHUNK"' is not supported", + protocol->name, ike_alg_type_name(alg->algo_type), + PRI_shunk(print_name)); return false; } /* @@ -69,16 +76,15 @@ * Since it likely involves a lookup, it is left until last. */ if (!ike_alg_is_valid(alg)) { - snprintf(parser->err_buf, parser->err_buf_len, - "%s %s algorithm '"PRI_SHUNK"' is not valid", - protocol->name, ike_alg_type_name(alg->algo_type), - PRI_shunk(print_name)); + proposal_error(parser, "%s %s algorithm '"PRI_SHUNK"' is not valid", + protocol->name, ike_alg_type_name(alg->algo_type), + PRI_shunk(print_name)); return false; } return true; } -static const struct ike_alg *alg_byname(const struct proposal_parser *parser, +static const struct ike_alg *alg_byname(struct proposal_parser *parser, const struct ike_alg_type *type, shunk_t name, shunk_t print_name) { @@ -91,15 +97,14 @@ */ if (ike_alg_enum_match(type, protocol->ikev1_alg_id, name) >= 0 || ike_alg_enum_match(type, IKEv2_ALG_ID, name) >= 0) { - snprintf(parser->err_buf, parser->err_buf_len, - "%s %s algorithm '"PRI_SHUNK"' is not supported", - protocol->name, ike_alg_type_name(type), - PRI_shunk(print_name)); + proposal_error(parser, "%s %s algorithm '"PRI_SHUNK"' is not supported", + protocol->name, ike_alg_type_name(type), + PRI_shunk(print_name)); + } else { - snprintf(parser->err_buf, parser->err_buf_len, - "%s %s algorithm '"PRI_SHUNK"' is not recognized", - protocol->name, ike_alg_type_name(type), - PRI_shunk(print_name)); + proposal_error(parser, "%s %s algorithm '"PRI_SHUNK"' is not recognized", + protocol->name, ike_alg_type_name(type), + PRI_shunk(print_name)); } return NULL; } @@ -108,14 +113,14 @@ * Does it pass muster? */ if (!alg_byname_ok(parser, alg, print_name)) { - passert(parser->err_buf[0] != '\0'); + passert(parser->error[0] != '\0'); return NULL; } return alg; } -const struct ike_alg *encrypt_alg_byname(const struct proposal_parser *parser, +const struct ike_alg *encrypt_alg_byname(struct proposal_parser *parser, shunk_t name, size_t key_bit_length, shunk_t print_name) { @@ -127,10 +132,9 @@ const struct encrypt_desc *encrypt = encrypt_desc(alg); if (!IMPAIR(SEND_KEY_SIZE_CHECK) && key_bit_length > 0) { if (encrypt->keylen_omitted) { - snprintf(parser->err_buf, parser->err_buf_len, - "%s does not take variable key lengths", - enum_short_name(&ikev2_trans_type_encr_names, - encrypt->common.id[IKEv2_ALG_ID])); + proposal_error(parser, "%s does not take variable key lengths", + enum_short_name(&ikev2_trans_type_encr_names, + encrypt->common.id[IKEv2_ALG_ID])); if (!impair_proposal_errors(parser)) { return NULL; } @@ -141,8 +145,7 @@ * should instead generate a real list from * encrypt. */ - snprintf(parser->err_buf, parser->err_buf_len, - "wrong encryption key length - key size must be 128 (default), 192 or 256"); + proposal_error(parser, "wrong encryption key length - key size must be 128 (default), 192 or 256"); if (!impair_proposal_errors(parser)) { return NULL; } @@ -151,21 +154,21 @@ return alg; } -const struct ike_alg *prf_alg_byname(const struct proposal_parser *parser, +const struct ike_alg *prf_alg_byname(struct proposal_parser *parser, shunk_t name, size_t key_bit_length UNUSED, shunk_t print_name) { return alg_byname(parser, IKE_ALG_PRF, name, print_name); } -const struct ike_alg *integ_alg_byname(const struct proposal_parser *parser, +const struct ike_alg *integ_alg_byname(struct proposal_parser *parser, shunk_t name, size_t key_bit_length UNUSED, shunk_t print_name) { return alg_byname(parser, IKE_ALG_INTEG, name, print_name); } -const struct ike_alg *dh_alg_byname(const struct proposal_parser *parser, +const struct ike_alg *dh_alg_byname(struct proposal_parser *parser, shunk_t name, size_t key_bit_length UNUSED, shunk_t print_name) { diff -Naur libreswan-3.27-orig/lib/libswan/alg_info.c libreswan-3.27/lib/libswan/alg_info.c --- libreswan-3.27-orig/lib/libswan/alg_info.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/lib/libswan/alg_info.c 1969-12-31 19:00:00.000000000 -0500 @@ -1,884 +0,0 @@ -/* - * Algorithm info parsing and creation functions - * Author: JuanJo Ciarlante - * - * Copyright (C) 2012 Paul Wouters - * Copyright (C) 2015-2018 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 "lswlog.h" -#include "lswalloc.h" -#include "constants.h" -#include "alg_info.h" -#include "ike_alg.h" -#include "ike_alg_integ.h" -#include "ike_alg_dh.h" -#include "alg_byname.h" - -/* - * Add the proposal defaults for the specific algorithm. - */ - -typedef struct proposal_info merge_alg_default_t(struct proposal_info proposal, - const struct ike_alg *default_alg); - -static struct proposal_info merge_dh_default(struct proposal_info proposal, - const struct ike_alg *default_alg) -{ - proposal.dh = oakley_group_desc(default_alg); - return proposal; -} - -static struct proposal_info merge_encrypt_default(struct proposal_info proposal, - const struct ike_alg *default_alg) -{ - proposal.encrypt = encrypt_desc(default_alg); - return proposal; -} - -static struct proposal_info merge_prf_default(struct proposal_info proposal, - const struct ike_alg *default_alg) -{ - proposal.prf = prf_desc(default_alg); - return proposal; -} - -static struct proposal_info merge_integ_default(struct proposal_info proposal, - const struct ike_alg *default_alg) -{ - proposal.integ = integ_desc(default_alg); - return proposal; -} - -static bool add_proposal_defaults(const struct proposal_parser *parser, - const struct proposal_defaults *defaults, - struct alg_info *alg_info, - const struct proposal_info *proposal); - -static bool add_alg_defaults(const struct proposal_parser *parser, - const struct proposal_defaults *defaults, - struct alg_info *alg_info, - const struct proposal_info *proposal, - const struct ike_alg_type *type, - const struct ike_alg **default_algs, - merge_alg_default_t *merge_alg_default) -{ - /* - * Use VALID_ALG to add the valid algorithms into VALID_ALGS. - */ - for (const struct ike_alg **default_alg = default_algs; - *default_alg; default_alg++) { - const struct ike_alg *alg = *default_alg; - if (!alg_byname_ok(parser, alg, - shunk1(alg->name))) { - DBG(DBG_PROPOSAL_PARSER, - DBG_log("skipping default %s", - parser->err_buf)); - parser->err_buf[0] = '\0'; - continue; - } - /* add it */ - DBG(DBG_PROPOSAL_PARSER, - DBG_log("adding default %s %s", - ike_alg_type_name(type), - alg->name)); - struct proposal_info merged_proposal = merge_alg_default(*proposal, - *default_alg); - if (!add_proposal_defaults(parser, defaults, - alg_info, &merged_proposal)) { - passert(parser->err_buf[0] != '\0'); - return false; - } - } - return true; -} - -/* - * Validate the proposal and, suppressing duplicates, add it to the - * proposal list. - */ - -static bool add_proposal(const struct proposal_parser *parser, - struct alg_info *alg_info, - const struct proposal_info *proposal) -{ - /* duplicate? */ - FOR_EACH_PROPOSAL_INFO(alg_info, existing_proposal) { - /* - * key length 0 is like a wild-card (it actually means - * propose default and strongest key lengths) so if - * either is zero just treat it as a match. - */ - if (existing_proposal->encrypt == proposal->encrypt && - existing_proposal->prf == proposal->prf && - existing_proposal->integ == proposal->integ && - existing_proposal->dh == proposal->dh && - (existing_proposal->enckeylen == proposal->enckeylen || - existing_proposal->enckeylen == 0 || - proposal->enckeylen == 0)) { - if (IMPAIR(PROPOSAL_PARSER)) { - libreswan_log("IMPAIR: including duplicate %s proposal encrypt=%s enckeylen=%zu prf=%s integ=%s dh=%s", - proposal->protocol->name, - proposal->encrypt != NULL ? proposal->encrypt->common.name : "n/a", - proposal->enckeylen, - proposal->prf != NULL ? proposal->prf->common.name : "n/a", - proposal->integ != NULL ? proposal->integ->common.name : "n/a", - proposal->dh != NULL ? proposal->dh->common.name : "n/a"); - } else { - DBG(DBG_CRYPT, - DBG_log("discarding duplicate %s proposal encrypt=%s enckeylen=%zu prf=%s integ=%s dh=%s", - proposal->protocol->name, - proposal->encrypt != NULL ? proposal->encrypt->common.name : "n/a", - proposal->enckeylen, - proposal->prf != NULL ? proposal->prf->common.name : "n/a", - proposal->integ != NULL ? proposal->integ->common.name : "n/a", - proposal->dh != NULL ? proposal->dh->common.name : "n/a")); - return true; - } - } - } - - /* Overflow? */ - if ((unsigned)alg_info->alg_info_cnt >= elemsof(alg_info->proposals)) { - snprintf(parser->err_buf, parser->err_buf_len, - "more than %zu %s algorithms specified", - elemsof(alg_info->proposals), - proposal->protocol->name); - /* drop it like a rock */ - return false; - } - - /* back end? */ - if (!proposal->protocol->proposal_ok(parser, proposal)) { - return false; - } - - alg_info->proposals[alg_info->alg_info_cnt++] = *proposal; - return true; -} - -/* - * For all the algorithms, when an algorithm is missing (NULL), and - * there are defaults, add them. - */ - -static bool add_proposal_defaults(const struct proposal_parser *parser, - const struct proposal_defaults *defaults, - struct alg_info *alg_info, - const struct proposal_info *proposal) -{ - /* - * Note that the order in which things are recursively added - - * MODP, ENCR, PRF/HASH - affects test results. It determines - * things like the order of proposals. - */ - if (proposal->dh == NULL && - defaults != NULL && defaults->dh != NULL) { - return add_alg_defaults(parser, defaults, - alg_info, proposal, - &ike_alg_dh, defaults->dh, - merge_dh_default); - } else if (proposal->encrypt == NULL && - defaults != NULL && defaults->encrypt != NULL) { - return add_alg_defaults(parser, defaults, - alg_info, proposal, - &ike_alg_encrypt, defaults->encrypt, - merge_encrypt_default); - } else if (proposal->prf == NULL && - defaults != NULL && defaults->prf != NULL) { - return add_alg_defaults(parser, defaults, - alg_info, proposal, - &ike_alg_prf, defaults->prf, - merge_prf_default); - } else if (proposal->integ == NULL && - proposal->encrypt != NULL && - encrypt_desc_is_aead(proposal->encrypt)) { - /* - * Since AEAD, integrity is always 'none'. - */ - struct proposal_info merged_proposal = *proposal; - merged_proposal.integ = &ike_alg_integ_none; - return add_proposal_defaults(parser, defaults, - alg_info, &merged_proposal); - } else if (proposal->integ == NULL && - defaults != NULL && defaults->integ != NULL) { - return add_alg_defaults(parser, defaults, - alg_info, proposal, - &ike_alg_integ, defaults->integ, - merge_integ_default); - } else if (proposal->integ == NULL && - proposal->prf != NULL && - proposal->encrypt != NULL && - !encrypt_desc_is_aead(proposal->encrypt)) { - /* - * Since non-AEAD, use an integrity algorithm that is - * implemented using the PRF. - */ - struct proposal_info merged_proposal = *proposal; - for (const struct integ_desc **algp = next_integ_desc(NULL); - algp != NULL; algp = next_integ_desc(algp)) { - const struct integ_desc *alg = *algp; - if (alg->prf == proposal->prf) { - merged_proposal.integ = alg; - break; - } - } - if (merged_proposal.integ == NULL) { - snprintf(parser->err_buf, parser->err_buf_len, - "%s integrity derived from PRF '%s' is not supported", - proposal->protocol->name, - proposal->prf->common.name); - return false; - } - return add_proposal_defaults(parser, defaults, - alg_info, &merged_proposal); - } else { - return add_proposal(parser, alg_info, proposal); - } -} - -static bool merge_default_proposals(const struct proposal_parser *parser, - struct alg_info *alg_info, - const struct proposal_info *proposal) -{ - /* - * If there's a hint of IKEv1 being enabled then prefer its - * larger set of defaults. - * - * This should increase the odds of both ends interoperating. - * - * For instance, the IKEv2 defaults were preferred and one end - * has ikev2=never then, in aggressive mode, things don't - * work. - */ - const struct proposal_defaults *defaults = (parser->policy->ikev1 - ? proposal->protocol->ikev1_defaults - : proposal->protocol->ikev2_defaults); - return add_proposal_defaults(parser, defaults, - alg_info, proposal); -} - -static const struct ike_alg *lookup_byname(const struct proposal_parser *parser, - alg_byname_fn *alg_byname, - shunk_t name, - size_t key_bit_length, - shunk_t print_name, - const char *what) -{ - if (name.len > 0) { - if (alg_byname != NULL) { - const struct ike_alg *alg = alg_byname(parser, name, key_bit_length, - print_name); - if (alg == NULL) { - DBG(DBG_PROPOSAL_PARSER, - DBG_log("%s_byname('"PRI_SHUNK"') failed: %s", - what, PRI_shunk(name), - parser->err_buf)); - passert(parser->err_buf[0] != '\0'); - return NULL; - } - DBG(DBG_PROPOSAL_PARSER, - DBG_log("%s_byname('"PRI_SHUNK"') returned '%s'", - what, PRI_shunk(name), alg->name)); - return alg; - } else { - DBG(DBG_PROPOSAL_PARSER, - DBG_log("ignoring %s '"PRI_SHUNK"'", - what, PRI_shunk(name))); - return NULL; - } - } - return NULL; -} - -static int parse_eklen(char *err_buf, size_t err_buf_len, - shunk_t buf) -{ - /* convert - if present */ - char *end = NULL; - long eklen = strtol(buf.ptr, &end, 10); - if (buf.ptr + buf.len != end) { - snprintf(err_buf, err_buf_len, - "encryption key length '"PRI_SHUNK"' contains a non-numeric character", - PRI_shunk(buf)); - return 0; - } - if (eklen >= INT_MAX) { - snprintf(err_buf, err_buf_len, - "encryption key length '"PRI_SHUNK"' WAY too big", - PRI_shunk(buf)); - return 0; - } - if (eklen == 0) { - snprintf(err_buf, err_buf_len, - "encryption key length is zero"); - return 0; - } - return eklen; -} - -/* - * Try to parse any of -, _, - * , or . Strings like aes_gcm_16 and - * aes_gcm_16_256 end up in alg[0], while strings like aes_gcm_16-256 - * end up in alg[0]-alg[1]. - */ - -struct token { - char sep; - shunk_t alg; -}; - -static bool parse_encrypt(const struct proposal_parser *parser, - struct token **tokens, - struct proposal_info *proposal) -{ - shunk_t ealg = (*tokens)[0].alg; - shunk_t eklen = (*tokens)[1].alg; - if (eklen.len > 0 && isdigit(eklen.ptr[0])) { - /* assume - */ - int enckeylen = parse_eklen(parser->err_buf, - parser->err_buf_len, - eklen); - if (enckeylen <= 0) { - passert(parser->err_buf[0] != '\0'); - return false; - } - /* print - */ - shunk_t print_name = shunk2(ealg.ptr, eklen.ptr + eklen.len - ealg.ptr); - proposal->enckeylen = enckeylen; - proposal->encrypt = - encrypt_desc(lookup_byname(parser, - encrypt_alg_byname, - ealg, proposal->enckeylen, - print_name, "encryption")); - /* Was - rejected? */ - if (parser->err_buf[0] != '\0') { - return false; - } - *tokens += 2; /* consume both tokens */ - return true; - } - /* try */ - shunk_t print_name = ealg; - proposal->encrypt = - encrypt_desc(lookup_byname(parser, - encrypt_alg_byname, - ealg, proposal->enckeylen, - print_name, "encryption")); - if (parser->err_buf[0] != '\0') { - /* - * Could it be or _? Work - * backwards skipping any digits. - */ - shunk_t end = shunk2(ealg.ptr + ealg.len, 0); - while (end.ptr > ealg.ptr && isdigit(end.ptr[-1])) { - end.ptr--; - end.len++; - } - if (end.len == 0) { - /* - * no trailing and was rejected - */ - passert(parser->err_buf[0] != '\0'); - return false; - } - /* try to convert */ - int enckeylen = parse_eklen(parser->err_buf, parser->err_buf_len, end); - if (enckeylen <= 0) { - passert(parser->err_buf[0] != '\0'); - return false; - } - proposal->enckeylen = enckeylen; - /* - * trim from ; and then trim any - * trailing '_' - */ - ealg.len = end.ptr - ealg.ptr; - if (end.ptr > ealg.ptr && end.ptr[-1] == '_') { - ealg.len -= 1; - } - /* try again */ - parser->err_buf[0] = '\0'; - proposal->encrypt = - encrypt_desc(lookup_byname(parser, - encrypt_alg_byname, - ealg, proposal->enckeylen, - print_name, "encryption")); - if (parser->err_buf[0] != '\0') { - return false; - } - } - *tokens += 1; /* consume one token */ - return true; -} - -static bool parser_alg_info_add(const struct proposal_parser *parser, - struct token *tokens, struct proposal_info proposal, - struct alg_info *alg_info) -{ - LSWDBGP(DBG_PROPOSAL_PARSER, buf) { - lswlogs(buf, "algs:"); - for (struct token *token = tokens; token->alg.ptr != NULL; token++) { - lswlogf(buf, " algs[%tu] = '"PRI_SHUNK"'", - token - tokens, PRI_shunk(token->alg)); - } - } - - bool lookup_encrypt = parser->protocol->encrypt_alg_byname != NULL; - if (!lookup_encrypt && IMPAIR(PROPOSAL_PARSER)) { - /* Force lookup, will discard any error. */ - lookup_encrypt = true; - } - if (lookup_encrypt && tokens->alg.ptr != NULL && tokens->sep != ';') { - if (!parse_encrypt(parser, &tokens, &proposal)) { - if (IMPAIR(PROPOSAL_PARSER)) { - /* ignore the lookup and stumble on */ - parser->err_buf[0] = '\0'; - } else { - passert(parser->err_buf[0] != '\0'); - return false; - } - } - } - - bool lookup_prf = parser->protocol->prf_alg_byname != NULL; - if (!lookup_prf && IMPAIR(PROPOSAL_PARSER)) { - /* - * Force PRF lookup when the folloing token looks like - * an INTEG algorithm (i.e., its lookup succeeds). - * Otherwise something like ah=sha1 gets parsed as - * ah=[encr]-sha1-[integ]-[dh]. - */ - shunk_t prf = tokens[0].alg; - shunk_t integ = tokens[1].alg; - if (prf.ptr != NULL && integ.ptr != NULL) { - lookup_prf = (lookup_byname(parser, integ_alg_byname, - integ, 0, integ, "integrity") - != NULL); - parser->err_buf[0] = '\0'; - } - } - if (lookup_prf && tokens->alg.ptr != NULL && tokens->sep != ';') { - shunk_t prf = tokens[0].alg; - proposal.prf = prf_desc(lookup_byname(parser, - prf_alg_byname, - prf, 0, prf, "PRF")); - if (parser->err_buf[0] != '\0') { - return false; - } - tokens += 1; /* consume one arg */ - } - - bool lookup_integ = parser->protocol->integ_alg_byname != NULL; - if (!lookup_integ && IMPAIR(PROPOSAL_PARSER)) { - /* force things */ - lookup_integ = true; - } - if (lookup_integ && tokens->alg.ptr != NULL && tokens->sep != ';') { - shunk_t integ = tokens[0].alg; - proposal.integ = integ_desc(lookup_byname(parser, - integ_alg_byname, - integ, 0, integ, "integrity")); - if (parser->err_buf[0] != '\0') { - if (tokens[1].alg.ptr != NULL) { - /* - * This alg should have been - * integrity, since the next would be - * DH; error applies. - */ - passert(parser->err_buf[0] != '\0'); - return false; - } - if (tokens[1].alg.ptr == NULL && - parser->protocol->prf_alg_byname == NULL) { - /* - * Only one arg, integrity is prefered - * to DH (and no PRF); error applies. - */ - passert(parser->err_buf[0] != '\0'); - return false; - } - /* let DH try */ - parser->err_buf[0] = '\0'; - } else { - tokens += 1; /* consume one arg */ - } - } - - bool lookup_dh = parser->protocol->dh_alg_byname || IMPAIR(PROPOSAL_PARSER); - if (lookup_dh && tokens->alg.ptr != NULL) { - shunk_t dh = tokens[0].alg; - proposal.dh = oakley_group_desc(lookup_byname(parser, - dh_alg_byname, - dh, 0, - dh, "DH")); - if (parser->err_buf[0] != '\0') { - return false; - } - tokens += 1; /* consume one arg */ - } - - if (tokens->alg.ptr != NULL) { - snprintf(parser->err_buf, parser->err_buf_len, - "'"PRI_SHUNK"' unexpected", - PRI_shunk(tokens[0].alg)); - return false; - } - - if (IMPAIR(PROPOSAL_PARSER)) { - return add_proposal(parser, alg_info, &proposal); - } else { - return merge_default_proposals(parser, alg_info, &proposal); - } -} - - -bool alg_info_parse_str(const struct proposal_parser *parser, - struct alg_info *alg_info, - shunk_t alg_str) -{ - DBG(DBG_PROPOSAL_PARSER, - DBG_log("parsing '"PRI_SHUNK"' for %s", - PRI_shunk(alg_str), parser->protocol->name)); - - /* use default if no string */ - if (alg_str.ptr == NULL) { - const struct proposal_info proposal = { - .protocol = parser->protocol, - }; - return merge_default_proposals(parser, alg_info, &proposal); - } - - if (alg_str.len == 0) { - /* XXX: hack to keep testsuite happy */ - snprintf(parser->err_buf, parser->err_buf_len, - "String ended with invalid char, just after \"\""); - return false; - } - - shunk_t prop_ptr = alg_str; - do { - /* find the next proposal */ - shunk_t prop = shunk_strsep(&prop_ptr, ","); - /* parse it */ - struct token tokens[8]; - zero(&tokens); - struct token *token = tokens; - char last_sep = '\0'; - shunk_t alg_ptr = prop; - do { - if (token + 1 >= tokens+elemsof(tokens)) { - /* space for NULL? */ - snprintf(parser->err_buf, parser->err_buf_len, - "proposal too long"); - return false; - } - /* find the next alg */ - shunk_t alg = shunk_strsep(&alg_ptr, "-;,"); - *token++ = (struct token) { - .alg = alg, - .sep = last_sep, - }; - last_sep = alg.ptr[alg.len]; /* save separator */ - } while (alg_ptr.len > 0); - struct proposal_info proposal = { - .protocol = parser->protocol, - }; - if (!parser_alg_info_add(parser, tokens, proposal, - alg_info)) { - passert(parser->err_buf[0] != '\0'); - return false; - } - } while (prop_ptr.len > 0); - return true; -} - -struct proposal_parser proposal_parser(const struct proposal_policy *policy, - const struct proposal_protocol *protocol, - char *err_buf, size_t err_buf_len) -{ - const struct proposal_parser parser = { - .policy = policy, - .protocol = protocol, - .err_buf = err_buf, - .err_buf_len = err_buf_len, - }; - err_buf[0] = '\0'; - return parser; -} - -bool proposal_aead_none_ok(const struct proposal_parser *parser, - const struct proposal_info *proposal) -{ - if (IMPAIR(ALLOW_NULL_NONE)) { - return true; - } - - if (proposal->encrypt != NULL && - encrypt_desc_is_aead(proposal->encrypt) && - proposal->integ != NULL && - proposal->integ != &ike_alg_integ_none) { - /* - * For instance, esp=aes_gcm-sha1" is invalid. - */ - snprintf(parser->err_buf, parser->err_buf_len, - "AEAD %s encryption algorithm '%s' must have 'none' as the integrity algorithm", - proposal->protocol->name, - proposal->encrypt->common.name); - return false; - } - - if (proposal->encrypt != NULL && - !encrypt_desc_is_aead(proposal->encrypt) && - proposal->integ != NULL && - proposal->integ == &ike_alg_integ_none) { - /* - * For instance, esp=aes_cbc-none" is invalid. - */ - snprintf(parser->err_buf, parser->err_buf_len, - "non-AEAD %s encryption algorithm '%s' cannot have 'none' as the integrity algorithm", - proposal->protocol->name, - proposal->encrypt->common.name); - return false; - } - - return true; -} - -/* - * alg_info struct can be shared by several connections instances, - * handle free() with ref_cnts. - * - * Use alg_info_free() if the value returned by *_parse_str() is found - * to be (semantically) bogus. - */ - -void alg_info_free(struct alg_info *alg_info) -{ - passert(alg_info); - passert(alg_info->ref_cnt == 0); - pfree(alg_info); -} - -void alg_info_addref(struct alg_info *alg_info) -{ - alg_info->ref_cnt++; -} - -void alg_info_delref(struct alg_info *alg_info) -{ - passert(alg_info->ref_cnt != 0); - alg_info->ref_cnt--; - if (alg_info->ref_cnt == 0) - alg_info_free(alg_info); -} - -size_t lswlog_proposal_info(struct lswlog *log, - const struct proposal_info *proposal) -{ - size_t size = 0; - const char *sep = ""; - - if (proposal->encrypt != NULL) { - size += lswlogs(log, sep); sep = "-"; - size += lswlogs(log, proposal->encrypt->common.fqn); - if (proposal->enckeylen != 0) { - size += lswlogf(log, "_%zd", proposal->enckeylen); - } - } else if (IMPAIR(PROPOSAL_PARSER)) { - size += lswlogs(log, sep); sep = "-"; - size += lswlogs(log, "[ENCRYPT]"); - } - - if (proposal->prf != NULL) { - size += lswlogs(log, sep); sep = "-"; - size += lswlogs(log, proposal->prf->common.fqn); - } else if (IMPAIR(PROPOSAL_PARSER)) { - size += lswlogs(log, sep); sep = "-"; - size += lswlogs(log, "[PRF]"); - } - - if (proposal->integ != NULL && proposal->prf == NULL) { - size += lswlogs(log, sep); sep = "-"; - size += lswlogs(log, proposal->integ->common.fqn); - } else if (!(proposal->integ == &ike_alg_integ_none && - encrypt_desc_is_aead(proposal->encrypt)) && - proposal->integ != NULL && proposal->integ->prf != proposal->prf) { - size += lswlogs(log, sep); sep = "-"; - size += lswlogs(log, proposal->integ->common.fqn); - } else if (IMPAIR(PROPOSAL_PARSER)) { - size += lswlogs(log, sep); sep = "-"; - if (proposal->integ != NULL) { - size += lswlogs(log, proposal->integ->common.fqn); - } else { - size += lswlogs(log, "[INTEG]"); - } - } - - if (proposal->dh != NULL) { - size += lswlogs(log, sep); sep = "-"; /* sep not subsequently used */ - size += lswlogs(log, proposal->dh->common.fqn); - } else if (IMPAIR(PROPOSAL_PARSER)) { - size += lswlogs(log, sep); sep = "-"; /* sep not subsequently used */ - size += lswlogs(log, "[DH]"); - } - - return size; -} - -size_t lswlog_alg_info(struct lswlog *log, const struct alg_info *alg_info) -{ - size_t size = 0; - const char *sep = ""; - FOR_EACH_PROPOSAL_INFO(alg_info, proposal) { - size += lswlogs(log, sep); - size += lswlog_proposal_info(log, proposal); - sep = ", "; - } - return size; -} - -/* - * When PFS=no ignore any DH algorithms, and when PFS=yes reject - * mixing implict and explicit DH. - */ -bool alg_info_pfs_vs_dh_check(const struct proposal_parser *parser, - struct alg_info_esp *aie) -{ - if (aie->ai.alg_info_cnt <= 0) { - /* let caller deal with no proposals. */ - return true; - } - - /* scrape the proposals for dh algorithms */ - struct proposal_info *first_null = NULL; - struct proposal_info *first_dh = NULL; - struct proposal_info *second_dh = NULL; - struct proposal_info *first_none = NULL; - FOR_EACH_ESP_INFO(aie, alg) { - if (alg->dh == NULL) { - if (first_null == NULL) { - first_null = alg; - } - } else if (alg->dh == &ike_alg_dh_none) { - if (first_none == NULL) { - first_none = alg; - } - } else if (first_dh == NULL) { - first_dh = alg; - } else if (second_dh == NULL && first_dh->dh != alg->dh) { - second_dh = alg; - } - } - - if (first_dh == NULL && first_none == NULL) { - /* no DH is always ok */ - return true; - } - - /* - * Try to generate very specific errors first. For instance, - * given PFS=no esp=aes,aes;dh21, an error stating that dh21 - * is not valid because of PFS is more helpful than an error - * saying that all or no proposals need PFS. - */ - - /* - * Since PFS=NO overrides any DH, don't silently ignore it. - * Check this early so that a conflict with PFS=no code gets - * reported before anything else. - */ - if (!parser->policy->pfs && (first_dh != NULL || first_none != NULL)) { - FOR_EACH_ESP_INFO(aie, alg) { - if (alg->dh == &ike_alg_dh_none) { - parser->policy->warning("ignoring redundant %s DH algorithm NONE as PFS policy is disabled", - parser->protocol->name); - } else if (alg->dh != NULL) { - parser->policy->warning("ignoring %s DH algorithm %s as PFS policy is disabled", - parser->protocol->name, - alg->dh->common.fqn); - } - alg->dh = NULL; - } - return true; - } - - /* - * Since at least one proposal included DH, all proposals - * should. A proposal without DH is an error. - * - * (The converse, no proposals including DH was handled right - * at the start). - */ - if (first_null != NULL) { - /* DH was specified */ - snprintf(parser->err_buf, parser->err_buf_len, - "either all or no %s proposals should specify DH", - parser->protocol->name); - if (!impair_proposal_errors(parser)) { - return false; - } - } - - /* - * IKEv1 only allows one DH algorithm. - */ - if (parser->policy->ikev1) { - if (first_dh != NULL && second_dh != NULL) { - snprintf(parser->err_buf, parser->err_buf_len, - "more than one IKEv1 %s DH algorithm (%s, %s) is not allowed in quick mode", - parser->protocol->name, - first_dh->dh->common.fqn, - second_dh->dh->common.fqn); - if (!impair_proposal_errors(parser)) { - return false; - } - } - } - - /* - * IKEv2, only implements one DH algorithm. - */ - if (parser->policy->ikev2) { - if (first_dh != NULL && second_dh != NULL) { - snprintf(parser->err_buf, parser->err_buf_len, - "more than one IKEv2 %s DH algorithm (%s, %s) requires unimplemented CHILD_SA INVALID_KE", - parser->protocol->name, - first_dh->dh->common.fqn, - second_dh->dh->common.fqn); - if (!impair_proposal_errors(parser)) { - return false; - } - } - } - - return true; -} - -bool impair_proposal_errors(const struct proposal_parser *parser) -{ - pexpect(parser->err_buf[0] != '\0'); - if (IMPAIR(PROPOSAL_PARSER)) { - libreswan_log("IMPAIR: ignoring proposal error: %s", - parser->err_buf); - parser->err_buf[0] = '\0'; - return true; - } else { - return false; - } -} diff -Naur libreswan-3.27-orig/lib/libswan/esp_info.c libreswan-3.27/lib/libswan/esp_info.c --- libreswan-3.27-orig/lib/libswan/esp_info.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/lib/libswan/esp_info.c 2019-02-15 16:50:12.776728076 -0500 @@ -22,7 +22,7 @@ #include "lswalloc.h" #include "lswlog.h" -#include "alg_info.h" +#include "proposals.h" #include "alg_byname.h" #include "lswfips.h" @@ -33,8 +33,8 @@ /* * Add ESP alg info _with_ logic (policy): */ -static bool esp_proposal_ok(const struct proposal_parser *parser, - const struct proposal_info *proposal) +static bool esp_proposal_ok(struct proposal_parser *parser, + const struct proposal *proposal) { if (!proposal_aead_none_ok(parser, proposal)) { if (!impair_proposal_errors(parser)) { @@ -42,12 +42,19 @@ } } - impaired_passert(PROPOSAL_PARSER, proposal->encrypt != NULL); - impaired_passert(PROPOSAL_PARSER, proposal->prf == NULL); - impaired_passert(PROPOSAL_PARSER, proposal->integ != NULL); + impaired_passert(PROPOSAL_PARSER, + next_algorithm(proposal, PROPOSAL_encrypt, NULL) != NULL); + impaired_passert(PROPOSAL_PARSER, + next_algorithm(proposal, PROPOSAL_prf, NULL) == NULL); + impaired_passert(PROPOSAL_PARSER, + next_algorithm(proposal, PROPOSAL_integ, NULL) != NULL); return true; } +/* + * since esp= must have an encryption algorithm this is normally + * ignored. + */ static const struct ike_alg *default_esp_encrypt[] = { #ifdef USE_AES &ike_alg_encrypt_aes_cbc.common, @@ -55,24 +62,39 @@ NULL, }; -static const struct ike_alg *default_esp_integ[] = { +static const struct ike_alg *default_v1_esp_integ[] = { #ifdef USE_SHA1 &ike_alg_integ_sha1.common, #endif NULL, }; -static const struct proposal_defaults esp_defaults = { +static const struct ike_alg *default_v2_esp_integ[] = { +#ifdef USE_SHA2 + &ike_alg_integ_sha2_512.common, + &ike_alg_integ_sha2_256.common, +#endif + NULL, +}; + +static const struct proposal_defaults v1_esp_defaults = { .encrypt = default_esp_encrypt, - .integ = default_esp_integ, + .integ = default_v1_esp_integ, +}; + +static const struct proposal_defaults v2_esp_defaults = { + .encrypt = default_esp_encrypt, + .integ = default_v2_esp_integ, }; static const struct proposal_protocol esp_proposal_protocol = { .name = "ESP", .ikev1_alg_id = IKEv1_ESP_ID, .protoid = PROTO_IPSEC_ESP, - .ikev1_defaults = &esp_defaults, - .ikev2_defaults = &esp_defaults, + .defaults = { + [IKEv1] = &v1_esp_defaults, + [IKEv2] = &v2_esp_defaults, + }, .proposal_ok = esp_proposal_ok, .encrypt_alg_byname = encrypt_alg_byname, .integ_alg_byname = integ_alg_byname, @@ -81,7 +103,7 @@ /* * ??? the only difference between - * alg_info_ah_create_from_str and alg_info_esp_create_from_str + * alg_info_ah_create_from_str and esp_proposals_create_from_str * is in the second argument to proposal_parser. * * XXX: On the other hand, since "struct ike_info" and "struct @@ -91,33 +113,7 @@ /* This function is tested in testing/algparse/algparse.c */ -struct alg_info_esp *alg_info_esp_create_from_str(const struct proposal_policy *policy, - const char *alg_str, - char *err_buf, size_t err_buf_len) +struct proposal_parser *esp_proposal_parser(const struct proposal_policy *policy) { - shunk_t string = shunk1(alg_str); - const struct proposal_parser parser = proposal_parser(policy, - &esp_proposal_protocol, - err_buf, err_buf_len); - - /* - * alg_info storage should be sized dynamically - * but this may require two passes to know - * transform count in advance. - */ - struct alg_info_esp *alg_info_esp = alloc_thing(struct alg_info_esp, - "alg_info_esp"); - if (!alg_info_parse_str(&parser, &alg_info_esp->ai, string)) { - passert(err_buf[0] != '\0'); - alg_info_free(&alg_info_esp->ai); - return NULL; - } - - if (!alg_info_pfs_vs_dh_check(&parser, alg_info_esp)) { - passert(err_buf[0] != '\0'); - alg_info_free(&alg_info_esp->ai); - return NULL; - } - - return alg_info_esp; + return alloc_proposal_parser(policy, &esp_proposal_protocol); } diff -Naur libreswan-3.27-orig/lib/libswan/ike_alg.c libreswan-3.27/lib/libswan/ike_alg.c --- libreswan-3.27-orig/lib/libswan/ike_alg.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/lib/libswan/ike_alg.c 2019-02-15 16:32:28.978835332 -0500 @@ -37,7 +37,7 @@ #include "ike_alg.h" #include "ike_alg_integ.h" #include "ike_alg_encrypt.h" -#include "alg_info.h" +#include "proposals.h" #include "ike_alg_prf.h" #include "ike_alg_prf_hmac_ops.h" #include "ike_alg_prf_nss_ops.h" @@ -589,7 +589,7 @@ static bool integ_desc_is_ike(const struct ike_alg *alg) { const struct integ_desc *integ = integ_desc(alg); - return integ->prf != NULL; + return integ->prf != NULL || integ == &ike_alg_integ_none; } static struct algorithm_table integ_algorithms = ALGORITHM_TABLE(integ_descriptors); diff -Naur libreswan-3.27-orig/lib/libswan/ike_alg_dh.c libreswan-3.27/lib/libswan/ike_alg_dh.c --- libreswan-3.27-orig/lib/libswan/ike_alg_dh.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/lib/libswan/ike_alg_dh.c 2019-02-15 16:32:28.979835342 -0500 @@ -186,7 +186,7 @@ .algo_type = IKE_ALG_DH, .name = "DH19", .fqn = "DH19", - .names = { "dh19", "ecp_256", }, + .names = { "dh19", "ecp_256", "ecp256" }, .id = { [IKEv1_OAKLEY_ID] = OAKLEY_GROUP_ECP_256, [IKEv1_ESP_ID] = -1, @@ -205,7 +205,7 @@ .algo_type = IKE_ALG_DH, .name = "DH20", .fqn = "DH20", - .names = { "dh20", "ecp_384", }, + .names = { "dh20", "ecp_384", "ecp384" }, .id = { [IKEv1_OAKLEY_ID] = OAKLEY_GROUP_ECP_384, [IKEv1_ESP_ID] = -1, @@ -224,7 +224,7 @@ .algo_type = IKE_ALG_DH, .name = "DH21", .fqn = "DH21", - .names = { "dh21", "ecp_521", }, + .names = { "dh21", "ecp_521", "ecp521" }, .id = { [IKEv1_OAKLEY_ID] = OAKLEY_GROUP_ECP_521, [IKEv1_ESP_ID] = -1, diff -Naur libreswan-3.27-orig/lib/libswan/ike_alg_sha2.c libreswan-3.27/lib/libswan/ike_alg_sha2.c --- libreswan-3.27-orig/lib/libswan/ike_alg_sha2.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/lib/libswan/ike_alg_sha2.c 2019-02-15 16:32:28.979835342 -0500 @@ -79,7 +79,7 @@ .common = { .name = "sha2_256", .fqn = "HMAC_SHA2_256_128", - .names = { "sha2", "sha256", "sha2_256", "hmac_sha2_256", "hmac_sha2_256_128", }, + .names = { "sha2", "sha256", "sha2_256", "sha2_256_128", "hmac_sha2_256", "hmac_sha2_256_128", }, .algo_type = IKE_ALG_INTEG, .id = { [IKEv1_OAKLEY_ID] = OAKLEY_SHA2_256, @@ -206,7 +206,7 @@ .common = { .name = "sha2_384", .fqn = "HMAC_SHA2_384_192", - .names = { "sha384", "sha2_384", "hmac_sha2_384", "hmac_sha2_384_192", }, + .names = { "sha384", "sha2_384", "sha2_384_192", "hmac_sha2_384", "hmac_sha2_384_192", }, .algo_type = IKE_ALG_INTEG, .id = { [IKEv1_OAKLEY_ID] = OAKLEY_SHA2_384, @@ -308,7 +308,7 @@ .common = { .name = "sha2_512", .fqn = "HMAC_SHA2_512_256", - .names = { "sha512", "sha2_512", "hmac_sha2_512", "hmac_sha2_512_256", }, + .names = { "sha512", "sha2_512", "sha2_512_256", "hmac_sha2_512", "hmac_sha2_512_256", }, .algo_type = IKE_ALG_INTEG, .id = { [IKEv1_OAKLEY_ID] = OAKLEY_SHA2_512, diff -Naur libreswan-3.27-orig/lib/libswan/ike_info.c libreswan-3.27/lib/libswan/ike_info.c --- libreswan-3.27-orig/lib/libswan/ike_info.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/lib/libswan/ike_info.c 2019-02-15 16:50:12.777728085 -0500 @@ -27,10 +27,10 @@ #include "ike_alg_integ.h" #include "ike_alg_prf.h" #include "ike_alg_dh.h" -#include "alg_info.h" +#include "proposals.h" -static bool ike_proposal_ok(const struct proposal_parser *parser, - const struct proposal_info *proposal) +static bool ike_proposal_ok(struct proposal_parser *parser, + const struct proposal *proposal) { if (!proposal_aead_none_ok(parser, proposal)) { if (!impair_proposal_errors(parser)) { @@ -42,27 +42,42 @@ * Check that the ALG_INFO spec is implemented. */ - impaired_passert(PROPOSAL_PARSER, proposal->encrypt != NULL); - passert(proposal->encrypt == NULL || ike_alg_is_ike(&(proposal->encrypt->common))); - passert(IMPAIR(PROPOSAL_PARSER) || proposal->enckeylen == 0 || - encrypt_has_key_bit_length(proposal->encrypt, - proposal->enckeylen)); - - impaired_passert(PROPOSAL_PARSER, proposal->prf != NULL); - passert(proposal->prf == NULL || ike_alg_is_ike(&(proposal->prf->common))); - - impaired_passert(PROPOSAL_PARSER, proposal->integ != NULL); - passert(proposal->integ == &ike_alg_integ_none || - proposal->integ == NULL || - ike_alg_is_ike(&proposal->integ->common)); - - impaired_passert(PROPOSAL_PARSER, proposal->dh != NULL); - passert(proposal->dh == NULL || ike_alg_is_ike(&(proposal->dh->common))); - if (proposal->dh == &ike_alg_dh_none) { - snprintf(parser->err_buf, parser->err_buf_len, - "IKE DH algorithm 'none' not permitted"); - if (!impair_proposal_errors(parser)) { - return false; + impaired_passert(PROPOSAL_PARSER, + next_algorithm(proposal, PROPOSAL_encrypt, NULL) != NULL); + FOR_EACH_ALGORITHM(proposal, encrypt, alg) { + const struct encrypt_desc *encrypt = encrypt_desc(alg->desc); + passert(ike_alg_is_ike(&encrypt->common)); + passert(IMPAIR(PROPOSAL_PARSER) || + alg->enckeylen == 0 || + encrypt_has_key_bit_length(encrypt, + alg->enckeylen)); + } + + impaired_passert(PROPOSAL_PARSER, + next_algorithm(proposal, PROPOSAL_prf, NULL) != NULL); + FOR_EACH_ALGORITHM(proposal, prf, alg) { + const struct prf_desc *prf = prf_desc(alg->desc); + passert(ike_alg_is_ike(&prf->common)); + } + + impaired_passert(PROPOSAL_PARSER, + next_algorithm(proposal, PROPOSAL_integ, NULL) != NULL); + FOR_EACH_ALGORITHM(proposal, integ, alg) { + const struct integ_desc *integ = integ_desc(alg->desc); + passert(integ == &ike_alg_integ_none || + ike_alg_is_ike(&integ->common)); + } + + impaired_passert(PROPOSAL_PARSER, + next_algorithm(proposal, PROPOSAL_dh, NULL) != NULL); + FOR_EACH_ALGORITHM(proposal, dh, alg) { + const struct oakley_group_desc *dh = dh_desc(alg->desc); + passert(ike_alg_is_ike(&dh->common)); + if (dh == &ike_alg_dh_none) { + proposal_error(parser, "IKE DH algorithm 'none' not permitted"); + if (!impair_proposal_errors(parser)) { + return false; + } } } @@ -84,9 +99,20 @@ }; static const struct ike_alg *default_ikev2_groups[] = { &oakley_group_modp2048.common, + &oakley_group_modp3072.common, + &oakley_group_modp4096.common, + &oakley_group_modp8192.common, + &oakley_group_dh19.common, + &oakley_group_dh20.common, + &oakley_group_dh21.common, + &oakley_group_dh31.common, NULL, }; +/* + * since ike= must have an encryption algorithm this is normally + * ignored. + */ static const struct ike_alg *default_ike_ealgs[] = { #ifdef USE_AES &ike_alg_encrypt_aes_cbc.common, @@ -97,7 +123,7 @@ NULL, }; -static const struct ike_alg *default_ike_aalgs[] = { +static const struct ike_alg *default_v1_ike_prfs[] = { #ifdef USE_SHA2 &ike_alg_prf_sha2_256.common, &ike_alg_prf_sha2_512.common, @@ -108,24 +134,34 @@ NULL, }; +static const struct ike_alg *default_v2_ike_prfs[] = { +#ifdef USE_SHA2 + &ike_alg_prf_sha2_512.common, + &ike_alg_prf_sha2_256.common, +#endif + NULL, +}; + const struct proposal_defaults ikev1_ike_defaults = { .dh = default_ikev1_groups, .encrypt = default_ike_ealgs, - .prf = default_ike_aalgs, + .prf = default_v1_ike_prfs, }; const struct proposal_defaults ikev2_ike_defaults = { .dh = default_ikev2_groups, .encrypt = default_ike_ealgs, - .prf = default_ike_aalgs, + .prf = default_v2_ike_prfs, }; const struct proposal_protocol ike_proposal_protocol = { .name = "IKE", .ikev1_alg_id = IKEv1_OAKLEY_ID, .protoid = PROTO_ISAKMP, - .ikev1_defaults = &ikev1_ike_defaults, - .ikev2_defaults = &ikev2_ike_defaults, + .defaults = { + [IKEv1] = &ikev1_ike_defaults, + [IKEv2] = &ikev2_ike_defaults, + }, .proposal_ok = ike_proposal_ok, .encrypt_alg_byname = encrypt_alg_byname, .prf_alg_byname = prf_alg_byname, @@ -133,25 +169,7 @@ .dh_alg_byname = dh_alg_byname, }; -struct alg_info_ike *alg_info_ike_create_from_str(const struct proposal_policy *policy, - const char *alg_str, - char *err_buf, size_t err_buf_len) +struct proposal_parser *ike_proposal_parser(const struct proposal_policy *policy) { - /* - * alg_info storage should be sized dynamically - * but this may require two passes to know - * transform count in advance. - */ - struct alg_info_ike *alg_info_ike = alloc_thing(struct alg_info_ike, "alg_info_ike"); - const struct proposal_parser parser = proposal_parser(policy, - &ike_proposal_protocol, - err_buf, err_buf_len); - - if (!alg_info_parse_str(&parser, &alg_info_ike->ai, shunk1(alg_str))) { - passert(err_buf[0] != '\0'); - alg_info_free(&alg_info_ike->ai); - return NULL; - } - - return alg_info_ike; + return alloc_proposal_parser(policy, &ike_proposal_protocol); } diff -Naur libreswan-3.27-orig/lib/libswan/Makefile libreswan-3.27/lib/libswan/Makefile --- libreswan-3.27-orig/lib/libswan/Makefile 2019-02-15 16:31:43.029408030 -0500 +++ libreswan-3.27/lib/libswan/Makefile 2019-02-15 16:32:28.981835360 -0500 @@ -74,7 +74,12 @@ OBJS += satot.o OBJS += ultot.o -OBJS += alg_info.o esp_info.o ike_info.o ah_info.o +OBJS += proposals.o +OBJS += v1_proposals.o +OBJS += v2_proposals.o +OBJS += esp_info.o +OBJS += ah_info.o +OBJS += ike_info.o OBJS += ckaid.o diff -Naur libreswan-3.27-orig/lib/libswan/proposals.c libreswan-3.27/lib/libswan/proposals.c --- libreswan-3.27-orig/lib/libswan/proposals.c 1969-12-31 19:00:00.000000000 -0500 +++ libreswan-3.27/lib/libswan/proposals.c 2019-02-15 16:46:01.378390204 -0500 @@ -0,0 +1,573 @@ +/* + * Algorithm info parsing and creation functions + * Author: JuanJo Ciarlante + * + * Copyright (C) 2012 Paul Wouters + * Copyright (C) 2015-2019 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 "lswlog.h" +#include "lswalloc.h" +#include "constants.h" +#include "proposals.h" +#include "ike_alg.h" +#include "ike_alg_integ.h" +#include "ike_alg_dh.h" +#include "alg_byname.h" + +struct proposal { + /* + * The algorithm entries. + */ + struct algorithm *algorithms[PROPOSAL_ALGORITHM_ROOF]; + /* + * Which protocol is this proposal intended for? + */ + const struct proposal_protocol *protocol; + struct proposal *next; +}; + +struct proposals { + int ref_cnt; + struct proposal *proposals; +}; + +struct proposal_parser *alloc_proposal_parser(const struct proposal_policy *policy, + const struct proposal_protocol *protocol) +{ + struct proposal_parser *parser = alloc_thing(struct proposal_parser, "parser"); + parser->policy = policy; + parser->protocol = protocol; + parser->error[0] = '\0'; + return parser; +} + +void free_proposal_parser(struct proposal_parser **parser) +{ + pfree(*parser); + *parser = NULL; +} + +bool proposal_encrypt_aead(const struct proposal *proposal) +{ + if (proposal->algorithms[PROPOSAL_encrypt] == NULL) { + return false; + } + FOR_EACH_ALGORITHM(proposal, encrypt, alg) { + const struct encrypt_desc *encrypt = encrypt_desc(alg->desc); + if (!encrypt_desc_is_aead(encrypt)) { + return false; + } + } + return true; +} + +bool proposal_encrypt_norm(const struct proposal *proposal) +{ + if (proposal->algorithms[PROPOSAL_encrypt] == NULL) { + return false; + } + FOR_EACH_ALGORITHM(proposal, encrypt, alg) { + const struct encrypt_desc *encrypt = encrypt_desc(alg->desc); + if (encrypt_desc_is_aead(encrypt)) { + return false; + } + } + return true; +} + +bool proposal_integ_none(const struct proposal *proposal) +{ + /* interpret NULL as NONE */ + FOR_EACH_ALGORITHM(proposal, integ, alg) { + const struct integ_desc *integ = integ_desc(alg->desc); + if (integ != &ike_alg_integ_none) { + return false; + } + } + return true; +} + +bool proposal_aead_none_ok(struct proposal_parser *parser, + const struct proposal *proposal) +{ + if (IMPAIR(ALLOW_NULL_NONE)) { + return true; + } + + if (proposal->algorithms[PROPOSAL_encrypt] == NULL) { + return true; + } + + /* are any and all encrypt algorithms AEAD? */ + bool aead = proposal_encrypt_aead(proposal); + bool norm = proposal_encrypt_norm(proposal); + + if (!aead && !norm) { + proposal_error(parser, "AEAD and non-AEAD %s encryption algorithm can not be combined", + proposal->protocol->name); + return false; + } + + /* are any and all integ algorithms NONE? */ + bool none = proposal_integ_none(proposal); + + if (aead && !none) { + const struct ike_alg *encrypt = proposal->algorithms[PROPOSAL_encrypt]->desc; + /* + * At least one of the integrity algorithms wasn't + * NONE. For instance, esp=aes_gcm-sha1" is invalid. + */ + proposal_error(parser, "AEAD %s encryption algorithm '%s' must have 'none' as the integrity algorithm", + proposal->protocol->name, + encrypt->name); + return false; + } + + if (norm && none) { + const struct ike_alg *encrypt = proposal->algorithms[PROPOSAL_encrypt]->desc; + /* + * Not AEAD and either there was no integrity + * algorithm (implying NONE) or at least one integrity + * algorithm was NONE. For instance, + * esp=aes_cbc-none" is invalid. + */ + proposal_error(parser, "non-AEAD %s encryption algorithm '%s' cannot have 'none' as the integrity algorithm", + proposal->protocol->name, + encrypt->name); + return false; + } + + return true; +} + + +/* + * proposals struct can be shared by several connections instances, + * handle free() with ref_cnts. + */ + +void proposals_addref(struct proposals **proposals) +{ + if ((*proposals) != NULL) { + (*proposals)->ref_cnt++; + } +} + +void proposals_delref(struct proposals **proposals) +{ + if ((*proposals) != NULL) { + if ((*proposals)->ref_cnt == 0) { + free_proposal(&(*proposals)->proposals); + pfree((*proposals)); + } else { + (*proposals)->ref_cnt--; + } + *proposals = NULL; + } +} +struct proposal *next_proposal(const struct proposals *proposals, + struct proposal *last) +{ + if (last == NULL) { + return proposals->proposals; + } else { + return last->next; + } +} + +unsigned nr_proposals(struct proposals *proposals) +{ + unsigned nr = 0; + FOR_EACH_PROPOSAL(proposals, proposal) { + nr++; + } + return nr; +} + +void append_proposal(struct proposals *proposals, struct proposal **proposal) +{ + struct proposal **end = &proposals->proposals; + /* check for duplicates */ + while ((*end) != NULL) { + bool same = true; + for (enum proposal_algorithm pa = 0; + same && pa < PROPOSAL_ALGORITHM_ROOF; pa++) { + struct algorithm *old = (*end)->algorithms[pa]; + struct algorithm *new = (*proposal)->algorithms[pa]; + while (same) { + if (new == NULL && old == NULL) { + break; + } + if (new == NULL || old == NULL) { + same = false; + break; + } + if (new->desc != old->desc) { + same = false; + break; + } + /* + * If list already contains encryption + * with ENCKEYLEN=0 then new is a + * duplicate as 0 generates all keys. + * Ignore reverse vis aes128,aes. + */ + if (old->desc->algo_type == IKE_ALG_ENCRYPT && + (old->enckeylen != 0 && + new->enckeylen != old->enckeylen)) { + same = false; + break; + } + new = new->next; + old = old->next; + } + } + if (same) { + /* parser->policy->warning("discarding duplicate proposal"); */ + free_proposal(proposal); + return; + } + end = &(*end)->next; + } + *end = *proposal; + *proposal = NULL; +} + +struct v1_proposal v1_proposal(const struct proposal *proposal) +{ + struct v1_proposal v1 = { + .protocol = proposal->protocol, +#define D(ALG) .ALG = proposal->algorithms[PROPOSAL_##ALG] != NULL ? ALG##_desc(proposal->algorithms[PROPOSAL_##ALG]->desc) : NULL + D(encrypt), + D(prf), + D(integ), + D(dh), +#undef D + }; + v1.enckeylen = proposal->algorithms[PROPOSAL_encrypt] != NULL ? proposal->algorithms[PROPOSAL_encrypt]->enckeylen : 0; + + return v1; +} + +struct algorithm *next_algorithm(const struct proposal *proposal, + enum proposal_algorithm algorithm, + struct algorithm *last) +{ + if (last == NULL) { + /* + * Hack, there should there a way to index algorithm + * types; however the old enum proved very dangerous. + */ + passert(algorithm < elemsof(proposal->algorithms)); + return proposal->algorithms[algorithm]; + } else { + return last->next; + } +} + +void free_algorithms(struct proposal *proposal, + enum proposal_algorithm algorithm) +{ + passert(algorithm < elemsof(proposal->algorithms)); + struct algorithm *alg = proposal->algorithms[algorithm]; + while (alg != NULL) { + struct algorithm *del = alg; + alg = alg->next; + pfree(del); + } + proposal->algorithms[algorithm] = NULL; +} + +struct proposal *alloc_proposal(struct proposal_parser *parser) +{ + struct proposal *proposal = alloc_thing(struct proposal, "proposal"); + proposal->protocol = parser->protocol; + return proposal; +} + +void free_proposal(struct proposal **proposals) +{ + struct proposal *proposal = *proposals; + while (proposal != NULL) { + struct proposal *del = proposal; + proposal = proposal->next; + for (enum proposal_algorithm algorithm = 0; + algorithm < PROPOSAL_ALGORITHM_ROOF; + algorithm++) { + free_algorithms(del, algorithm); + } + pfree(del); + } + *proposals = NULL; +} + +void append_algorithm(struct proposal_parser *parser, + struct proposal *proposal, + enum proposal_algorithm algorithm, + const struct ike_alg *alg, + int enckeylen) +{ + passert(algorithm < elemsof(proposal->algorithms)); + struct algorithm **end = &proposal->algorithms[algorithm]; + /* find end, and check for duplicates */ + while ((*end) != NULL) { + /* + * enckeylen=0 acts as a wildcard + */ + if (alg == (*end)->desc && + (alg->algo_type != IKE_ALG_ENCRYPT || + ((*end)->enckeylen == 0 || + enckeylen == (*end)->enckeylen))) { + parser->policy->warning("discarding duplicate algorithm '%s'", + alg->name); + return; + } + end = &(*end)->next; + } + struct algorithm new_algorithm = { + .desc = alg, + .enckeylen = enckeylen, + }; + *end = clone_thing(new_algorithm, "alg"); +} + +void fmt_proposal(struct lswlog *log, + const struct proposal *proposal) +{ + const char *ps = ""; + + const char *as = ""; + + as = ps; + FOR_EACH_ALGORITHM(proposal, encrypt, alg) { + const struct encrypt_desc *encrypt = encrypt_desc(alg->desc); + lswlogs(log, as); ps = "-"; as = "+"; + lswlogs(log, encrypt->common.fqn); + if (alg->enckeylen != 0) { + lswlogf(log, "_%d", alg->enckeylen); + } + } + + as = ps; + FOR_EACH_ALGORITHM(proposal, prf, alg) { + const struct prf_desc *prf = prf_desc(alg->desc); + lswlogs(log, as); ps = "-"; as = "+"; + lswlogs(log, prf->common.fqn); + } + + as = ps; + if ((proposal->algorithms[PROPOSAL_prf] == NULL && + proposal->algorithms[PROPOSAL_integ] != NULL) || + (IMPAIR(PROPOSAL_PARSER) && + proposal->algorithms[PROPOSAL_integ] != NULL)) { + FOR_EACH_ALGORITHM(proposal, integ, alg) { + const struct integ_desc *integ = integ_desc(alg->desc); + lswlogs(log, as); ps = "-"; as = "+"; + lswlogs(log, integ->common.fqn); + } + } + + as = ps; + FOR_EACH_ALGORITHM(proposal, dh, alg) { + const struct oakley_group_desc *dh = dh_desc(alg->desc); + lswlogs(log, as); ps = "-"; as = "+"; + lswlogs(log, dh->common.fqn); + } +} + +void fmt_proposals(struct lswlog *log, const struct proposals *proposals) +{ + const char *sep = ""; + FOR_EACH_PROPOSAL(proposals, proposal) { + lswlogs(log, sep); + fmt_proposal(log, proposal); + sep = ", "; + } +} + +/* + * When PFS=no ignore any DH algorithms, and when PFS=yes reject + * mixing implict and explicit DH. + */ +static bool proposals_pfs_vs_dh_check(struct proposal_parser *parser, + struct proposals *proposals) +{ + /* scrape the proposals for dh algorithms */ + const struct proposal *first_null = NULL; + const struct proposal *first_none = NULL; + const struct ike_alg *first_dh = NULL; + const struct ike_alg *second_dh = NULL; + FOR_EACH_PROPOSAL(proposals, proposal) { + if (proposal->algorithms[PROPOSAL_dh] == NULL) { + if (first_null == NULL) { + first_null = proposal; + } + } else if (proposal->algorithms[PROPOSAL_dh]->desc == &ike_alg_dh_none.common) { + if (first_none == NULL) { + first_none = proposal; + } + } else if (first_dh == NULL) { + first_dh = proposal->algorithms[PROPOSAL_dh]->desc; + } else if (second_dh == NULL && + first_dh != proposal->algorithms[PROPOSAL_dh]->desc) { + second_dh = proposal->algorithms[PROPOSAL_dh]->desc; + } + } + + if (first_dh == NULL && first_none == NULL) { + /* no DH is always ok */ + return true; + } + + /* + * Try to generate very specific errors first. For instance, + * given PFS=no esp=aes,aes;dh21, an error stating that dh21 + * is not valid because of PFS is more helpful than an error + * saying that all or no proposals need PFS. + */ + + /* + * Since PFS=NO overrides any DH, don't silently ignore it. + * Check this early so that a conflict with PFS=no code gets + * reported before anything else. + */ + if (!parser->policy->pfs && (first_dh != NULL || first_none != NULL)) { + FOR_EACH_PROPOSAL(proposals, proposal) { + const struct ike_alg *dh = NULL; + if (proposal->algorithms[PROPOSAL_dh] != NULL) { + dh = proposal->algorithms[PROPOSAL_dh]->desc; + } + if (dh == &ike_alg_dh_none.common) { + parser->policy->warning("ignoring redundant %s DH algorithm NONE as PFS policy is disabled", + parser->protocol->name); + } else if (dh != NULL) { + parser->policy->warning("ignoring %s DH algorithm %s as PFS policy is disabled", + parser->protocol->name, + dh->fqn); + } + free_algorithms(proposal, PROPOSAL_dh); + } + return true; + } + + /* + * Since at least one proposal included DH, all proposals + * should. A proposal without DH is an error. + * + * (The converse, no proposals including DH was handled right + * at the start). + */ + if (first_null != NULL) { + /* DH was specified */ + proposal_error(parser, "either all or no %s proposals should specify DH", + parser->protocol->name); + if (!impair_proposal_errors(parser)) { + return false; + } + } + + switch (parser->policy->version) { + + case IKEv1: + /* + * IKEv1 only allows one DH algorithm. + */ + if (first_dh != NULL && second_dh != NULL) { + proposal_error(parser, "more than one IKEv1 %s DH algorithm (%s, %s) is not allowed in quick mode", + parser->protocol->name, + first_dh->fqn, + second_dh->fqn); + if (!impair_proposal_errors(parser)) { + return false; + } + } + break; + + case IKEv2: + /* + * IKEv2, only implements one DH algorithm. + */ + if (first_dh != NULL && second_dh != NULL) { + proposal_error(parser, "more than one IKEv2 %s DH algorithm (%s, %s) requires unimplemented CHILD_SA INVALID_KE", + parser->protocol->name, + first_dh->fqn, + second_dh->fqn); + if (!impair_proposal_errors(parser)) { + return false; + } + } + break; + + default: + /* ignore */ + break; + } + + return true; +} + +void proposal_error(struct proposal_parser *parser, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vsnprintf(parser->error, sizeof(parser->error), fmt, ap); + va_end(ap); +} + +bool impair_proposal_errors(struct proposal_parser *parser) +{ + pexpect(parser->error[0] != '\0'); + if (IMPAIR(PROPOSAL_PARSER)) { + libreswan_log("IMPAIR: ignoring proposal error: %s", + parser->error); + parser->error[0] = '\0'; + return true; + } else { + return false; + } +} + +struct proposals *proposals_from_str(struct proposal_parser *parser, + const char *str) +{ + struct proposals *proposals = alloc_thing(struct proposals, "proposals"); + unsigned parser_version = parser->policy->parser_version; + if (parser_version == 0) { + parser_version = parser->policy->version; + } + bool ok; + switch (parser_version) { + case 2: ok = v2_proposals_parse_str(parser, proposals, shunk1(str)); break; + default: ok = v1_proposals_parse_str(parser, proposals, shunk1(str)); break; + } + if (!ok) { + proposals_delref(&proposals); + return NULL; + } + if (proposals->proposals == NULL) { + proposals_delref(&proposals); + return NULL; + } + if (parser->policy->check_pfs_vs_dh && + !proposals_pfs_vs_dh_check(parser, proposals)) { + pexpect(parser->error[0] != '\0'); + proposals_delref(&proposals); + return NULL; + } + return proposals; +} diff -Naur libreswan-3.27-orig/lib/libswan/shunk.c libreswan-3.27/lib/libswan/shunk.c --- libreswan-3.27-orig/lib/libswan/shunk.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/lib/libswan/shunk.c 2019-02-15 16:32:28.982835370 -0500 @@ -1,6 +1,6 @@ -/* string fragments, for libreswan +/* Constant string (octet) fragments, for libreswan * - * Copyright (C) 2018 Andrew Cagney + * Copyright (C) 2018-2019 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 @@ -20,12 +20,17 @@ #include "shunk.h" -const shunk_t empty_shunk; +/* + * Don't mistake a NULL_SHUNK for an empty shunk - just like for + * strings they are different. + */ + +const shunk_t null_shunk = NULL_SHUNK; shunk_t shunk1(const char *ptr) { if (ptr == NULL) { - return empty_shunk; + return null_shunk; } else { return shunk2(ptr, strlen(ptr)); } @@ -34,28 +39,37 @@ shunk_t shunk2(const char *ptr, int len) { /* - * Since a zero length string and a NULL string pointer are - * considered to be different, don't convert the former into - * an empty_chunk. + * Since a zero length string is not the same as a NULL + * string, don't try to be smart and convert the former into + * the latter. */ return (shunk_t) { .ptr = ptr, .len = len, }; } -shunk_t shunk_strsep(shunk_t *shunk, const char *delim) +shunk_t shunk_strsep(shunk_t *input, const char *delim) { - shunk_t token = shunk2(shunk->ptr, 0); - while (shunk->len > 0) { - if (strchr(delim, *shunk->ptr) != NULL) { + /* + * If INPUT is NULL, the loop is skipped and NULL is + * returned. + */ + shunk_t token = shunk2(input->ptr, 0); + while (input->len > 0) { + if (strchr(delim, *input->ptr) != NULL) { /* discard delim */ - shunk->ptr++; - shunk->len--; + input->ptr++; + input->len--; return token; } /* advance, transfering the char */ token.len++; - shunk->ptr++; - shunk->len--; + input->ptr++; + input->len--; } + /* + * Flag this as the last token by setting INPUT to NULL; next + * call will return the NULL shunk. + */ + *input = null_shunk; return token; } diff -Naur libreswan-3.27-orig/lib/libswan/v1_proposals.c libreswan-3.27/lib/libswan/v1_proposals.c --- libreswan-3.27-orig/lib/libswan/v1_proposals.c 1969-12-31 19:00:00.000000000 -0500 +++ libreswan-3.27/lib/libswan/v1_proposals.c 2019-02-15 16:47:22.485144451 -0500 @@ -0,0 +1,578 @@ +/* V1 algorithm proposal parsing, for libreswan + * + * Copyright (C) 2012 Paul Wouters + * Copyright (C) 2015-2019 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 "lswlog.h" +#include "lswalloc.h" +#include "constants.h" +#include "proposals.h" +#include "ike_alg.h" +#include "ike_alg_integ.h" +#include "ike_alg_dh.h" +#include "alg_byname.h" + +/* + * Add the proposal defaults for the specific algorithm. + */ + +typedef struct v1_proposal merge_alg_default_t(struct v1_proposal proposal, + const struct ike_alg *default_alg); + +static struct v1_proposal merge_dh_default(struct v1_proposal proposal, + const struct ike_alg *default_alg) +{ + proposal.dh = oakley_group_desc(default_alg); + return proposal; +} + +static struct v1_proposal merge_encrypt_default(struct v1_proposal proposal, + const struct ike_alg *default_alg) +{ + proposal.encrypt = encrypt_desc(default_alg); + return proposal; +} + +static struct v1_proposal merge_prf_default(struct v1_proposal proposal, + const struct ike_alg *default_alg) +{ + proposal.prf = prf_desc(default_alg); + return proposal; +} + +static struct v1_proposal merge_integ_default(struct v1_proposal proposal, + const struct ike_alg *default_alg) +{ + proposal.integ = integ_desc(default_alg); + return proposal; +} + +static bool add_proposal_defaults(struct proposal_parser *parser, + const struct proposal_defaults *defaults, + struct proposals *proposals, + const struct v1_proposal *proposal); + +static bool add_alg_defaults(struct proposal_parser *parser, + const struct proposal_defaults *defaults, + struct proposals *proposals, + const struct v1_proposal *proposal, + const struct ike_alg_type *type, + const struct ike_alg **default_algs, + merge_alg_default_t *merge_alg_default) +{ + /* + * Use VALID_ALG to add the valid algorithms into VALID_ALGS. + */ + for (const struct ike_alg **default_alg = default_algs; + *default_alg; default_alg++) { + const struct ike_alg *alg = *default_alg; + if (!alg_byname_ok(parser, alg, + shunk1(alg->name))) { + DBG(DBG_PROPOSAL_PARSER, + DBG_log("skipping default %s", + parser->error)); + parser->error[0] = '\0'; + continue; + } + /* add it */ + DBG(DBG_PROPOSAL_PARSER, + DBG_log("adding default %s %s", + ike_alg_type_name(type), + alg->name)); + struct v1_proposal merged_proposal = merge_alg_default(*proposal, + *default_alg); + if (!add_proposal_defaults(parser, defaults, + proposals, &merged_proposal)) { + passert(parser->error[0] != '\0'); + return false; + } + } + return true; +} + +/* + * Validate the proposal and, suppressing duplicates, add it to the + * proposal list. + */ + +static bool add_proposal(struct proposal_parser *parser, + struct proposals *proposals, + const struct v1_proposal *proposal) +{ + struct proposal *new = alloc_proposal(parser); + if (proposal->encrypt != NULL) { + append_algorithm(parser, new, PROPOSAL_encrypt, + &proposal->encrypt->common, + proposal->enckeylen); + } +#define A(NAME) \ + if (proposal->NAME != NULL) { \ + append_algorithm(parser, new, PROPOSAL_##NAME, \ + &proposal->NAME->common, 0); \ + } + A(prf); + A(integ); + A(dh); +#undef A + /* back end? */ + if (!proposal->protocol->proposal_ok(parser, new)) { + free_proposal(&new); + return false; + } + append_proposal(proposals, &new); + return true; +} + +/* + * For all the algorithms, when an algorithm is missing (NULL), and + * there are defaults, add them. + */ + +static bool add_proposal_defaults(struct proposal_parser *parser, + const struct proposal_defaults *defaults, + struct proposals *proposals, + const struct v1_proposal *proposal) +{ + /* + * Note that the order in which things are recursively added - + * MODP, ENCR, PRF/HASH - affects test results. It determines + * things like the order of proposals. + */ + if (proposal->dh == NULL && + defaults != NULL && defaults->dh != NULL) { + return add_alg_defaults(parser, defaults, + proposals, proposal, + &ike_alg_dh, defaults->dh, + merge_dh_default); + } else if (proposal->encrypt == NULL && + defaults != NULL && defaults->encrypt != NULL) { + return add_alg_defaults(parser, defaults, + proposals, proposal, + &ike_alg_encrypt, defaults->encrypt, + merge_encrypt_default); + } else if (proposal->prf == NULL && + defaults != NULL && defaults->prf != NULL) { + return add_alg_defaults(parser, defaults, + proposals, proposal, + &ike_alg_prf, defaults->prf, + merge_prf_default); + } else if (proposal->integ == NULL && + proposal->encrypt != NULL && + encrypt_desc_is_aead(proposal->encrypt)) { + /* + * Since AEAD, integrity is always 'none'. + */ + struct v1_proposal merged_proposal = *proposal; + merged_proposal.integ = &ike_alg_integ_none; + return add_proposal_defaults(parser, defaults, + proposals, &merged_proposal); + } else if (proposal->integ == NULL && + defaults != NULL && defaults->integ != NULL) { + return add_alg_defaults(parser, defaults, + proposals, proposal, + &ike_alg_integ, defaults->integ, + merge_integ_default); + } else if (proposal->integ == NULL && + proposal->prf != NULL && + proposal->encrypt != NULL && + !encrypt_desc_is_aead(proposal->encrypt)) { + /* + * Since non-AEAD, use an integrity algorithm that is + * implemented using the PRF. + */ + struct v1_proposal merged_proposal = *proposal; + for (const struct integ_desc **algp = next_integ_desc(NULL); + algp != NULL; algp = next_integ_desc(algp)) { + const struct integ_desc *alg = *algp; + if (alg->prf == proposal->prf) { + merged_proposal.integ = alg; + break; + } + } + if (merged_proposal.integ == NULL) { + proposal_error(parser, "%s integrity derived from PRF '%s' is not supported", + proposal->protocol->name, + proposal->prf->common.name); + return false; + } + return add_proposal_defaults(parser, defaults, + proposals, &merged_proposal); + } else { + return add_proposal(parser, proposals, proposal); + } +} + +static bool merge_default_proposals(struct proposal_parser *parser, + struct proposals *proposals, + const struct v1_proposal *proposal) +{ + /* + * If there's a hint of IKEv1 being enabled then prefer its + * larger set of defaults. + * + * This should increase the odds of both ends interoperating. + * + * For instance, the IKEv2 defaults were preferred and one end + * has ikev2=never then, in aggressive mode, things don't + * work. + */ + passert(parser->policy->version < elemsof(proposal->protocol->defaults)); + const struct proposal_defaults *defaults = + proposal->protocol->defaults[parser->policy->version]; + return add_proposal_defaults(parser, defaults, + proposals, proposal); +} + +static const struct ike_alg *lookup_byname(struct proposal_parser *parser, + alg_byname_fn *alg_byname, + shunk_t name, + size_t key_bit_length, + shunk_t print_name, + const char *what) +{ + if (name.len > 0) { + if (alg_byname != NULL) { + const struct ike_alg *alg = alg_byname(parser, name, key_bit_length, + print_name); + if (alg == NULL) { + DBG(DBG_PROPOSAL_PARSER, + DBG_log("%s_byname('"PRI_SHUNK"') failed: %s", + what, PRI_shunk(name), + parser->error)); + passert(parser->error[0] != '\0'); + return NULL; + } + DBG(DBG_PROPOSAL_PARSER, + DBG_log("%s_byname('"PRI_SHUNK"') returned '%s'", + what, PRI_shunk(name), alg->name)); + return alg; + } else { + DBG(DBG_PROPOSAL_PARSER, + DBG_log("ignoring %s '"PRI_SHUNK"'", + what, PRI_shunk(name))); + return NULL; + } + } + return NULL; +} + +static int parse_eklen(struct proposal_parser *parser, shunk_t buf) +{ + /* convert - if present */ + char *end = NULL; + long eklen = strtol(buf.ptr, &end, 10); + if (buf.ptr + buf.len != end) { + proposal_error(parser, "encryption key length '"PRI_SHUNK"' contains a non-numeric character", + PRI_shunk(buf)); + return 0; + } + if (eklen >= INT_MAX) { + proposal_error(parser, "encryption key length '"PRI_SHUNK"' WAY too big", + PRI_shunk(buf)); + return 0; + } + if (eklen == 0) { + proposal_error(parser, "encryption key length is zero"); + return 0; + } + return eklen; +} + +/* + * Try to parse any of -, _, + * , or . Strings like aes_gcm_16 and + * aes_gcm_16_256 end up in alg[0], while strings like aes_gcm_16-256 + * end up in alg[0]-alg[1]. + */ + +struct token { + char sep; + shunk_t alg; +}; + +static bool parse_encrypt(struct proposal_parser *parser, + struct token **tokens, + struct v1_proposal *proposal) +{ + shunk_t ealg = (*tokens)[0].alg; + shunk_t eklen = (*tokens)[1].alg; + if (eklen.len > 0 && isdigit(eklen.ptr[0])) { + /* assume - */ + int enckeylen = parse_eklen(parser, eklen); + if (enckeylen <= 0) { + passert(parser->error[0] != '\0'); + return false; + } + /* print - */ + shunk_t print_name = shunk2(ealg.ptr, eklen.ptr + eklen.len - ealg.ptr); + proposal->enckeylen = enckeylen; + proposal->encrypt = + encrypt_desc(lookup_byname(parser, + encrypt_alg_byname, + ealg, proposal->enckeylen, + print_name, "encryption")); + /* Was - rejected? */ + if (parser->error[0] != '\0') { + return false; + } + *tokens += 2; /* consume both tokens */ + return true; + } + /* try */ + shunk_t print_name = ealg; + proposal->encrypt = + encrypt_desc(lookup_byname(parser, + encrypt_alg_byname, + ealg, proposal->enckeylen, + print_name, "encryption")); + if (parser->error[0] != '\0') { + /* + * Could it be or _? Work + * backwards skipping any digits. + */ + shunk_t end = shunk2(ealg.ptr + ealg.len, 0); + while (end.ptr > ealg.ptr && isdigit(end.ptr[-1])) { + end.ptr--; + end.len++; + } + if (end.len == 0) { + /* + * no trailing and was rejected + */ + passert(parser->error[0] != '\0'); + return false; + } + /* try to convert */ + int enckeylen = parse_eklen(parser, end); + if (enckeylen <= 0) { + passert(parser->error[0] != '\0'); + return false; + } + proposal->enckeylen = enckeylen; + /* + * trim from ; and then trim any + * trailing '_' + */ + ealg.len = end.ptr - ealg.ptr; + if (end.ptr > ealg.ptr && end.ptr[-1] == '_') { + ealg.len -= 1; + } + /* try again */ + parser->error[0] = '\0'; + proposal->encrypt = + encrypt_desc(lookup_byname(parser, + encrypt_alg_byname, + ealg, proposal->enckeylen, + print_name, "encryption")); + if (parser->error[0] != '\0') { + return false; + } + } + *tokens += 1; /* consume one token */ + return true; +} + +static bool parser_proposals_add(struct proposal_parser *parser, + struct token *tokens, struct v1_proposal proposal, + struct proposals *proposals) +{ + LSWDBGP(DBG_PROPOSAL_PARSER, buf) { + lswlogs(buf, "algs:"); + for (struct token *token = tokens; token->alg.ptr != NULL; token++) { + lswlogf(buf, " algs[%tu] = '"PRI_SHUNK"'", + token - tokens, PRI_shunk(token->alg)); + } + } + + bool lookup_encrypt = parser->protocol->encrypt_alg_byname != NULL; + if (!lookup_encrypt && IMPAIR(PROPOSAL_PARSER)) { + /* Force lookup, will discard any error. */ + lookup_encrypt = true; + } + if (lookup_encrypt && tokens->alg.ptr != NULL && tokens->sep != ';') { + if (!parse_encrypt(parser, &tokens, &proposal)) { + if (IMPAIR(PROPOSAL_PARSER)) { + /* ignore the lookup and stumble on */ + parser->error[0] = '\0'; + } else { + passert(parser->error[0] != '\0'); + return false; + } + } + } + + bool lookup_prf = parser->protocol->prf_alg_byname != NULL; + if (!lookup_prf && IMPAIR(PROPOSAL_PARSER)) { + /* + * When impaired, only force PRF lookup when the the + * token after this one is a valid INTEG algorithm. + * Otherwise something like ah=sha1 gets parsed as + * ah=[encr]-sha1-[integ]-[dh] instead of + * ah=[encr]-[prf]-sha1-[dh]. + */ + shunk_t prf = tokens[0].alg; + shunk_t integ = tokens[1].alg; + if (prf.ptr != NULL && integ.ptr != NULL) { + lookup_prf = (lookup_byname(parser, integ_alg_byname, + integ, 0, integ, "integrity") + != NULL); + parser->error[0] = '\0'; + } + } + if (lookup_prf && tokens->alg.ptr != NULL && tokens->sep != ';') { + shunk_t prf = tokens[0].alg; + proposal.prf = prf_desc(lookup_byname(parser, + prf_alg_byname, + prf, 0, prf, "PRF")); + if (parser->error[0] != '\0') { + return false; + } + tokens += 1; /* consume one arg */ + } + + /* + * By default, don't allow IKE's [...]---[....]. + * Instead fill in integrity using the above PRF. + * + * XXX: The parser and output isn't consistent in that for ESP + * it parses - but for IKE it parses + * -. This seems to lead to confusion when + * printing proposals - ike=aes_gcm-sha1 gets mis-read as as + * using sha1 as integrity. ike-aes_gcm-none-sha1 would + * clarify this but that makes for a fun parse. + */ + bool lookup_integ = (parser->protocol->prf_alg_byname == NULL && + parser->protocol->integ_alg_byname != NULL); + if (!lookup_integ && IMPAIR(PROPOSAL_PARSER)) { + /* force things */ + lookup_integ = true; + } + if (lookup_integ && tokens->alg.ptr != NULL && tokens->sep != ';') { + shunk_t integ = tokens[0].alg; + proposal.integ = integ_desc(lookup_byname(parser, + integ_alg_byname, + integ, 0, integ, "integrity")); + if (parser->error[0] != '\0') { + if (tokens[1].alg.ptr != NULL) { + /* + * This alg should have been + * integrity, since the next would be + * DH; error applies. + */ + passert(parser->error[0] != '\0'); + return false; + } + if (tokens[1].alg.ptr == NULL && + parser->protocol->prf_alg_byname == NULL) { + /* + * Only one arg, integrity is prefered + * to DH (and no PRF); error applies. + */ + passert(parser->error[0] != '\0'); + return false; + } + /* let DH try */ + parser->error[0] = '\0'; + } else { + tokens += 1; /* consume one arg */ + } + } + + bool lookup_dh = parser->protocol->dh_alg_byname || IMPAIR(PROPOSAL_PARSER); + if (lookup_dh && tokens->alg.ptr != NULL) { + shunk_t dh = tokens[0].alg; + proposal.dh = oakley_group_desc(lookup_byname(parser, + dh_alg_byname, + dh, 0, + dh, "DH")); + if (parser->error[0] != '\0') { + return false; + } + tokens += 1; /* consume one arg */ + } + + if (tokens->alg.ptr != NULL) { + proposal_error(parser, "'"PRI_SHUNK"' unexpected", + PRI_shunk(tokens[0].alg)); + return false; + } + + if (IMPAIR(PROPOSAL_PARSER)) { + return add_proposal(parser, proposals, &proposal); + } else { + return merge_default_proposals(parser, proposals, &proposal); + } +} + +bool v1_proposals_parse_str(struct proposal_parser *parser, + struct proposals *proposals, + shunk_t alg_str) +{ + DBG(DBG_PROPOSAL_PARSER, + DBG_log("parsing '"PRI_SHUNK"' for %s", + PRI_shunk(alg_str), parser->protocol->name)); + + /* use default if no string */ + if (alg_str.ptr == NULL) { + const struct v1_proposal proposal = { + .protocol = parser->protocol, + }; + return merge_default_proposals(parser, proposals, &proposal); + } + + if (alg_str.len == 0) { + /* XXX: hack to keep testsuite happy */ + proposal_error(parser, "String ended with invalid char, just after \"\""); + return false; + } + + shunk_t prop_ptr = alg_str; + do { + /* find the next proposal */ + shunk_t prop = shunk_strsep(&prop_ptr, ","); + /* parse it */ + struct token tokens[8]; + zero(&tokens); + struct token *token = tokens; + char last_sep = '\0'; + shunk_t alg_ptr = prop; + do { + if (token + 1 >= tokens+elemsof(tokens)) { + /* space for NULL? */ + proposal_error(parser, "proposal too long"); + return false; + } + /* find the next alg */ + shunk_t alg = shunk_strsep(&alg_ptr, "-;,"); + *token++ = (struct token) { + .alg = alg, + .sep = last_sep, + }; + last_sep = alg.ptr[alg.len]; /* save separator */ + } while (alg_ptr.len > 0); + struct v1_proposal proposal = { + .protocol = parser->protocol, + }; + if (!parser_proposals_add(parser, tokens, proposal, + proposals)) { + passert(parser->error[0] != '\0'); + return false; + } + } while (prop_ptr.len > 0); + return true; +} diff -Naur libreswan-3.27-orig/lib/libswan/v2_proposals.c libreswan-3.27/lib/libswan/v2_proposals.c --- libreswan-3.27-orig/lib/libswan/v2_proposals.c 1969-12-31 19:00:00.000000000 -0500 +++ libreswan-3.27/lib/libswan/v2_proposals.c 2019-02-15 16:49:23.278267768 -0500 @@ -0,0 +1,398 @@ +/* V2 algorithm proposal parsing, for libreswan + * + * Copyright (C) 2019 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 "lswlog.h" +#include "lswalloc.h" +#include "constants.h" +#include "proposals.h" +#include "ike_alg.h" +#include "ike_alg_integ.h" +#include "ike_alg_dh.h" +#include "alg_byname.h" + +/* + * For all the algorithms, when an algorithm is missing (NULL), and + * there are defaults, add them. + */ + +static void merge_algorithms(struct proposal_parser *parser, + struct proposal *proposal, + enum proposal_algorithm algorithm, + const struct ike_alg **defaults) +{ + if (defaults == NULL) { + return; + } + if (next_algorithm(proposal, algorithm, NULL) != NULL) { + return; + } + for (const struct ike_alg **alg = defaults; (*alg) != NULL; alg++) { + append_algorithm(parser, proposal, algorithm, *alg, 0); + } +} + +static bool merge_defaults(struct proposal_parser *parser, + struct proposal *proposal) +{ + pexpect(parser->policy->version < elemsof(parser->protocol->defaults)); + const struct proposal_defaults *defaults = + parser->protocol->defaults[parser->policy->version]; + merge_algorithms(parser, proposal, PROPOSAL_encrypt, defaults->encrypt); + merge_algorithms(parser, proposal, PROPOSAL_prf, defaults->prf); + if (next_algorithm(proposal, PROPOSAL_integ, NULL) == NULL) { + if (proposal_encrypt_aead(proposal)) { + /* + * Since AEAD, integrity is always 'none'. + */ + append_algorithm(parser, proposal, PROPOSAL_integ, + &ike_alg_integ_none.common, 0); + } else if (defaults->integ != NULL) { + /* + * Merge in the defaults. + */ + merge_algorithms(parser, proposal, PROPOSAL_integ, + defaults->integ); + } else if (next_algorithm(proposal, PROPOSAL_prf, NULL) != NULL && + proposal_encrypt_norm(proposal)) { + /* + * Since non-AEAD, use integrity algorithms + * that are implemented using the PRFs. + */ + FOR_EACH_ALGORITHM(proposal, prf, prf) { + const struct integ_desc *integ = NULL; + for (const struct integ_desc **integp = next_integ_desc(NULL); + integp != NULL; integp = next_integ_desc(integp)) { + if ((*integp)->prf != NULL && + &(*integp)->prf->common == prf->desc) { + integ = *integp; + break; + } + } + if (integ == NULL) { + proposal_error(parser, "%s integrity derived from PRF '%s' is not supported", + parser->protocol->name, + prf->desc->name); + return false; + } + append_algorithm(parser, proposal, PROPOSAL_integ, + &integ->common, 0); + } + } + } + merge_algorithms(parser, proposal, PROPOSAL_dh, defaults->dh); + return true; +} + +static bool parse_alg(struct proposal_parser *parser, + struct proposal *proposal, + enum proposal_algorithm algorithm, + alg_byname_fn *alg_byname, + shunk_t token, int enckeylen, shunk_t print, + const char *what) +{ + if (alg_byname == NULL) { + /* n/a */ + return false; + } + if (token.len == 0) { + /* will error at end */ + return false; + } + const struct ike_alg *alg = alg_byname(parser, token, enckeylen, print); + if (alg == NULL) { + if (DBGP(DBG_PROPOSAL_PARSER)) { + DBG_log("%s_byname('"PRI_SHUNK"') failed: %s", + what, PRI_shunk(token), + parser->error); + } + pexpect(parser->error[0] != '\0'); + return false; + } + DBGF(DBG_PROPOSAL_PARSER, "adding %s algorithm %s[_%d]", + what, alg->name, enckeylen); + append_algorithm(parser, proposal, algorithm, alg, enckeylen); + return true; +} + +/* + * tokenize into + */ + +struct token { + char delim; + shunk_t alg; + shunk_t input; +}; + +static void next(struct token *token) +{ + if (token->delim == '\0') { + /* first call, set delim to something bogus */ + token->delim = ' '; + } else { + token->delim = token->input.ptr != NULL ? token->input.ptr[-1] : ' '; + } + token->alg = shunk_strsep(&token->input, "-;+"); + if (DBGP(DBG_PROPOSAL_PARSER)) { + if (token->alg.ptr == NULL) { + DBG_log("delim: n/a alg: end-of-input"); + } else { + DBG_log("delim: '%c' alg: '"PRI_SHUNK"'", + token->delim, PRI_shunk(token->alg)); + } + } +} + +/* + * Try to parse any of -, _, + * , or using some look-ahead. + */ + +static int parse_eklen(struct proposal_parser *parser, shunk_t buf) +{ + /* convert - if present */ + char *end = NULL; + long eklen = strtol(buf.ptr, &end, 10); + if (buf.ptr + buf.len != end) { + proposal_error(parser, "encryption key length '"PRI_SHUNK"' contains a non-numeric character", + PRI_shunk(buf)); + return 0; + } + if (eklen >= INT_MAX) { + proposal_error(parser, "encryption key length '"PRI_SHUNK"' WAY too big", + PRI_shunk(buf)); + return 0; + } + if (eklen == 0) { + proposal_error(parser, "encryption key length is zero"); + return 0; + } + return eklen; +} + +static bool parse_encrypt(struct proposal_parser *parser, + struct proposal *proposal, struct token *token) +{ + alg_byname_fn *alg_byname = parser->protocol->encrypt_alg_byname; + if (alg_byname == NULL) { + return false; + } + if (token->alg.len == 0) { + return false; + } + shunk_t ealg = token->alg; + /* try - using look-ahead? */ + struct token lookahead = *token; + next(&lookahead); + if (lookahead.delim == '-' && + lookahead.alg.len > 0 && + isdigit(lookahead.alg.ptr[0])) { + shunk_t eklen = lookahead.alg; + /* assume - */ + int enckeylen = parse_eklen(parser, eklen); + if (enckeylen <= 0) { + pexpect(parser->error[0] != '\0'); + return false; + } + /* print "-" in errors */ + shunk_t print_name = shunk2(ealg.ptr, eklen.ptr + eklen.len - ealg.ptr); + if (!parse_alg(parser, proposal, PROPOSAL_encrypt, alg_byname, + ealg, enckeylen, print_name, "encrypt")) { + return false; + } + *token = lookahead; + return true; + } + /* try (no key len) */ + shunk_t print_name = token->alg; + if (!parse_alg(parser, proposal, PROPOSAL_encrypt, alg_byname, + ealg, 0, print_name, "encrypt")) { + /* + * Could it be or _? Work + * backwards skipping any digits. + */ + shunk_t end = shunk2(ealg.ptr + ealg.len, 0); + while (end.ptr > ealg.ptr && isdigit(end.ptr[-1])) { + end.ptr--; + end.len++; + } + if (end.len == 0) { + /* + * no trailing and was rejected + */ + pexpect(parser->error[0] != '\0'); + return false; + } + /* try to convert */ + int enckeylen = parse_eklen(parser, end); + if (enckeylen <= 0) { + pexpect(parser->error[0] != '\0'); + return false; + } + /* + * trim from ; and then trim any + * trailing '_' + */ + ealg.len = end.ptr - ealg.ptr; + if (end.ptr > ealg.ptr && end.ptr[-1] == '_') { + ealg.len -= 1; + } + /* try again */ + if (!parse_alg(parser, proposal, PROPOSAL_encrypt, alg_byname, + ealg, enckeylen, print_name, "encrypt")) { + return false; + } + } + return true; +} + +static bool parse_proposal(struct proposal_parser *parser, + struct proposals *proposals UNUSED, shunk_t input) +{ + if (DBGP(DBG_PROPOSAL_PARSER)) { + DBG_log("proposal: '"PRI_SHUNK"'", PRI_shunk(input)); + } + + char error[sizeof(parser->error)] = ""; + struct proposal *proposal = alloc_proposal(parser); + + struct token token = { + .input = input, + }; + next(&token); + /* + * Encryption is not optional. + */ + bool lookup_encrypt = parser->protocol->encrypt_alg_byname != NULL; + if (lookup_encrypt) { + if (!parse_encrypt(parser, proposal, &token)) { + free_proposal(&proposal); + return false; + } + error[0] = parser->error[0] = '\0'; + next(&token); + while (token.delim == '+' && + parse_encrypt(parser, proposal, &token)) { + error[0] = parser->error[0] = '\0'; + next(&token); + } + } +#define PARSE_ALG(STOP, ALG) \ + if (error[0] == '\0' && parser->error[0] != '\0') { \ + strcpy(error, parser->error); \ + DBGF(DBG_PROPOSAL_PARSER, "saved first error: %s", error); \ + } \ + if (token.delim != STOP && \ + parse_alg(parser, proposal, PROPOSAL_##ALG, \ + parser->protocol->ALG##_alg_byname, \ + token.alg, 0, token.alg, #ALG)) { \ + error[0] = parser->error[0] = '\0'; \ + next(&token); \ + while (token.delim == '+' && \ + parse_alg(parser, proposal, PROPOSAL_##ALG, \ + parser->protocol->ALG##_alg_byname, \ + token.alg, 0, token.alg, #ALG)) { \ + error[0] = parser->error[0] = '\0'; \ + next(&token); \ + } \ + } + PARSE_ALG(';', prf); + /* + * By default, don't allow ike=...---... but do + * allow esp=...-. In the case of IKE, when integrity + * is required, it is filled in using the PRF. + * + * XXX: The parser and output isn't consistent in that for ESP + * it parses - but for IKE it parses + * -. This seems to lead to confusion when + * printing proposals - ike=aes_gcm-sha1 gets mis-read as as + * using sha1 as integrity. ike-aes_gcm-none-sha1 would + * clarify this but that makes for a fun parse. + */ + if (parser->protocol->prf_alg_byname == NULL || + IMPAIR(PROPOSAL_PARSER)) { + PARSE_ALG(';', integ); + } + PARSE_ALG('\0', dh); + if (error[0] != '\0') { + DBGF(DBG_PROPOSAL_PARSER, "return first error: %s", error); + free_proposal(&proposal); + strcpy(parser->error, error); + return false; + } + if (parser->error[0] != '\0') { + DBGF(DBG_PROPOSAL_PARSER, "return last error: %s", parser->error); + free_proposal(&proposal); + return false; + } + if (token.alg.ptr != NULL) { + proposal_error(parser, "'"PRI_SHUNK"' unexpected", + PRI_shunk(token.alg)); + free_proposal(&proposal); + return false; + } + if (!IMPAIR(PROPOSAL_PARSER) && + !merge_defaults(parser, proposal)) { + free_proposal(&proposal); + return false; + } + /* back end? */ + if (!parser->protocol->proposal_ok(parser, proposal)) { + free_proposal(&proposal); + return false; + } + append_proposal(proposals, &proposal); + return true; +} + +bool v2_proposals_parse_str(struct proposal_parser *parser, + struct proposals *proposals, + shunk_t input) +{ + DBG(DBG_PROPOSAL_PARSER, + DBG_log("parsing '"PRI_SHUNK"' for %s", + PRI_shunk(input), parser->protocol->name)); + + /* use default if no string */ + if (input.ptr == NULL) { + struct proposal *proposal = alloc_proposal(parser); + if (!merge_defaults(parser, proposal)) { + free_proposal(&proposal); + return false; + } + append_proposal(proposals, &proposal); + return true; + } + + if (input.len == 0) { + /* XXX: hack to keep testsuite happy */ + proposal_error(parser, "String ended with invalid char, just after \"\""); + return false; + } + + do { + /* find the next proposal */ + shunk_t proposal = shunk_strsep(&input, ","); + if (!parse_proposal(parser, proposals, proposal)) { + pexpect(parser->error[0] != '\0'); + return false; + } + } while (input.len > 0); + return true; +} diff -Naur libreswan-3.27-orig/programs/algparse/algparse.c libreswan-3.27/programs/algparse/algparse.c --- libreswan-3.27-orig/programs/algparse/algparse.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/algparse/algparse.c 2019-02-15 16:49:23.278267768 -0500 @@ -9,15 +9,15 @@ #include "lswconf.h" #include "ike_alg.h" -#include "alg_info.h" +#include "proposals.h" static bool test_proposals = false; static bool test_algs = false; static bool verbose = false; static bool debug = false; static bool impair = false; -static bool ikev1 = false; -static bool ikev2 = false; +static enum ike_version ike_version = IKEv2; +static unsigned parser_version = 0; static bool fips = false; static bool pfs = false; static int failures = 0; @@ -25,23 +25,23 @@ enum status { PASSED = 0, FAILED = 1, ERROR = 126, }; enum expect { FAIL = false, PASS = true, COUNT, }; -#define CHECK(TYPE,PARSE,OK) { \ +#define CHECK(CHECK,PARSE,OK) { \ struct proposal_policy policy = { \ - .ikev1 = ikev1, \ - .ikev2 = ikev2, \ + .version = ike_version, \ + .parser_version = parser_version, \ .alg_is_ok = OK, \ .pfs = pfs, \ .warning = warning, \ + .check_pfs_vs_dh = CHECK, \ }; \ printf("algparse "); \ if (fips) { \ printf("-fips "); \ } \ - if (ikev1) { \ - printf("-v1 "); \ - } \ - if (ikev2) { \ - printf("-v2 "); \ + switch (ike_version) { \ + case IKEv1: printf("-v1 "); break; \ + case IKEv2: printf("-v2 "); break; \ + default: break; \ } \ if (pfs) { \ printf("-pfs "); \ @@ -52,21 +52,19 @@ printf("'%s=%s'\n", #PARSE, algstr); \ } \ fflush(NULL); \ - char err_buf[512] = ""; /* ??? big enough? */ \ - struct alg_info_##TYPE *e = \ - alg_info_##PARSE##_create_from_str(&policy, \ - algstr, \ - err_buf, \ - sizeof(err_buf)); \ - if (e != NULL) { \ - passert(err_buf[0] == '\0'); \ - FOR_EACH_PROPOSAL_INFO(&e->ai, proposal) { \ + struct proposal_parser *parser = \ + PARSE##_proposal_parser(&policy); \ + struct proposals *proposals = \ + proposals_from_str(parser, algstr); \ + if (proposals != NULL) { \ + pexpect(parser->error[0] == '\0'); \ + FOR_EACH_PROPOSAL(proposals, proposal) { \ LSWLOG_FILE(stdout, log) { \ lswlogf(log, "\t"); \ - lswlog_proposal_info(log, proposal); \ + fmt_proposal(log, proposal); \ } \ } \ - alg_info_free(&e->ai); \ + proposals_delref(&proposals); \ if (expected == FAIL) { \ failures++; \ fprintf(stderr, \ @@ -76,8 +74,8 @@ algstr == NULL ? "" : algstr); \ } \ } else { \ - passert(err_buf[0]); \ - printf("\tERROR: %s\n", err_buf); \ + pexpect(parser->error[0]); \ + printf("\tERROR: %s\n", parser->error); \ if (expected == PASS) { \ failures++; \ fprintf(stderr, \ @@ -89,6 +87,7 @@ failures++; \ } \ } \ + free_proposal_parser(&parser); \ fflush(NULL); \ } @@ -122,17 +121,17 @@ static void esp(enum expect expected, const char *algstr) { - CHECK(esp, esp, kernel_alg_is_ok); + CHECK(true, esp, kernel_alg_is_ok); } static void ah(enum expect expected, const char *algstr) { - CHECK(esp, ah, kernel_alg_is_ok); + CHECK(true, ah, kernel_alg_is_ok); } static void ike(enum expect expected, const char *algstr) { - CHECK(ike, ike, ike_alg_is_ike); + CHECK(false, ike, ike_alg_is_ike); } typedef void (protocol_t)(enum expect expected, const char *); @@ -203,8 +202,8 @@ esp(!fips, "3des-sha1;modp1024"); esp(!fips, "3des-sha1;modp1536"); esp(true, "3des-sha1;modp2048"); - esp(!ikev1, "3des-sha1;dh21"); - esp(!ikev1, "3des-sha1;ecp_521"); + esp(ike_version == IKEv2, "3des-sha1;dh21"); + esp(ike_version == IKEv2, "3des-sha1;ecp_521"); esp(false, "3des-sha1;dh23"); esp(false, "3des-sha1;dh24"); esp(true, "3des-sha1"); @@ -218,7 +217,7 @@ esp(true, "aes-sha384"); esp(true, "aes-sha512"); esp(true, "aes128-sha1"); - esp(true, "aes128-aes_xcbc"); + esp(!fips, "aes128-aes_xcbc"); esp(true, "aes192-sha1"); esp(true, "aes256-sha1"); esp(true, "aes256-sha"); @@ -300,18 +299,18 @@ esp(!fips, "twofish"); esp(!fips, "camellia_cbc_256-hmac_sha2_512_256;modp8192"); /* long */ - esp(!fips, "null_auth_aes_gmac_256-null;modp8192"); /* long */ + esp(true, "null_auth_aes_gmac_256-null;modp8192"); /* long */ esp(true, "3des-sha1;modp8192"); /* allow ';' when unambigious */ esp(true, "3des-sha1-modp8192"); /* allow '-' when unambigious */ esp(!pfs, "aes-sha1,3des-sha1;modp8192"); esp(true, "aes-sha1-modp8192,3des-sha1-modp8192"); /* silly */ esp(true, "aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192"); /* suppress duplicates */ - esp(!ikev1, "aes;none"); - esp(!ikev1 && !pfs, "aes;none,aes"); - esp(!ikev1, "aes;none,aes;modp2048"); - esp(!ikev1, "aes-sha1-none"); - esp(!ikev1, "aes-sha1;none"); + esp(ike_version == IKEv2, "aes;none"); + esp(ike_version == IKEv2 && !pfs, "aes;none,aes"); + esp(ike_version == IKEv2, "aes;none,aes;modp2048"); + esp(ike_version == IKEv2, "aes-sha1-none"); + esp(ike_version == IKEv2, "aes-sha1;none"); /* * should this be supported - for now man page says not @@ -374,9 +373,9 @@ ah(true, "sha2_256"); ah(true, "sha2_384"); ah(true, "sha2_512"); - ah(true, "aes_xcbc"); - ah(!ikev1, "sha2-none"); - ah(!ikev1, "sha2;none"); + ah(!fips, "aes_xcbc"); + ah(ike_version == IKEv2, "sha2-none"); + ah(ike_version == IKEv2, "sha2;none"); ah(true, "sha1-modp8192,sha1-modp8192,sha1-modp8192"); /* suppress duplicates */ ah(impair, "aes-sha1"); ah(false, "vanityhash1"); @@ -400,12 +399,15 @@ ike(true, "3des;dh21"); ike(true, "3des-sha1;dh21"); ike(true, "3des-sha1-ecp_521"); - ike(!ikev1, "aes_gcm"); + ike(ike_version == IKEv2, "aes_gcm"); ike(true, "aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192"); /* suppress duplicates */ ike(false, "aes;none"); ike(false, "id2"); /* should be rejected; idXXX removed */ ike(false, "3des-id2"); /* should be rejected; idXXX removed */ ike(false, "aes_ccm"); /* ESP/AH only */ + ike(impair, "aes_gcm-sha1-none-modp2048"); + ike(impair, "aes_gcm+aes_gcm-sha1-none-modp2048"); + ike(false, "aes+aes_gcm"); /* mixing AEAD and NORM encryption */ } static void usage(void) @@ -432,9 +434,8 @@ "\n" "Additional options:\n" "\n" - " -v1 | -ikev1: require IKEv1 support\n" - " -v2 | -ikev2: require IKEv2 support\n" - " default: require either IKEv1 or IKEv2 support\n" + " -v2 | -ikev2: configure for IKEv2 (default)\n" + " -v1 | -ikev1: configure for IKEv1\n" " -pfs | -pfs=yes | -pfs=no: specify PFS (perfect forward privicy)\n" " default: no\n" " -fips | -fips=yes | -fips=no: force NSS's FIPS mode\n" @@ -446,6 +447,8 @@ " -v --verbose: be more verbose\n" " -d --debug: enable debug logging\n" " -i --impair: disable all algorithm parser checks\n" + " -p1: simple parser\n" + " -p2: complex parser\n" "\n" "Examples:\n" "\n" @@ -483,10 +486,14 @@ test_proposals = true; } else if (streq(arg, "ta")) { test_algs = true; + } else if (streq(arg, "p1")) { + parser_version = 1; + } else if (streq(arg, "p2")) { + parser_version = 2; } else if (streq(arg, "v1") || streq(arg, "ikev1")) { - ikev1 = true; + ike_version = IKEv1; } else if (streq(arg, "v2") || streq(arg, "ikev2")) { - ikev2 = true; + ike_version = IKEv2; } else if (streq(arg, "pfs") || streq(arg, "pfs=yes") || streq(arg, "pfs=on")) { pfs = true; } else if (streq(arg, "pfs=no") || streq(arg, "pfs=off")) { diff -Naur libreswan-3.27-orig/programs/pluto/connections.c libreswan-3.27/programs/pluto/connections.c --- libreswan-3.27-orig/programs/pluto/connections.c 2019-02-15 16:31:43.031408048 -0500 +++ libreswan-3.27/programs/pluto/connections.c 2019-02-15 16:32:28.986835407 -0500 @@ -69,7 +69,7 @@ #include "peerlog.h" #include "keys.h" #include "whack.h" -#include "alg_info.h" +#include "proposals.h" #include "spdb.h" #include "ike_alg.h" #include "kernel_alg.h" @@ -352,17 +352,13 @@ sr = next_sr; } - if (c->alg_info_ike != NULL) { - alg_info_delref(&c->alg_info_ike->ai); - c->alg_info_ike = NULL; - } - free_ikev2_proposals(&c->ike_proposals); + proposals_delref(&c->ike_proposals.p); + proposals_delref(&c->child_proposals.p); - if (c->alg_info_esp != NULL) { - alg_info_delref(&c->alg_info_esp->ai); - c->alg_info_esp = NULL; - } - free_ikev2_proposals(&c->esp_or_ah_proposals); + free_ikev2_proposals(&c->v2_ike_proposals); + free_ikev2_proposals(&c->v2_ike_auth_child_proposals); + free_ikev2_proposals(&c->v2_create_child_proposals); + c->v2_create_child_proposals_default_dh = NULL; /* static pointer */ pfree(c); } @@ -807,11 +803,8 @@ } /* increment references to algo's, if any */ - if (c->alg_info_ike != NULL) - alg_info_addref(&c->alg_info_ike->ai); - - if (c->alg_info_esp != NULL) - alg_info_addref(&c->alg_info_esp->ai); + proposals_addref(&c->ike_proposals.p); + proposals_addref(&c->child_proposals.p); if (c->pool != NULL) reference_addresspool(c); @@ -1496,8 +1489,6 @@ c->connalias = wm->connalias; c->dnshostname = wm->dnshostname; c->policy = wm->policy; - c->alg_info_ike = NULL; - c->alg_info_esp = NULL; c->sighash_policy = wm->sighash_policy; if (NEVER_NEGOTIATE(c->policy)) { @@ -1556,49 +1547,35 @@ /* IKE cipher suites */ if (!LIN(POLICY_AUTH_NEVER, wm->policy) && wm->ike != NULL) { - char err_buf[256] = ""; /* ??? big enough? */ const struct proposal_policy proposal_policy = { - .ikev1 = LIN(POLICY_IKEV1_ALLOW, wm->policy), - /* - * logic needs to match pick_initiator() - * - * XXX: Once pluto is changed to IKEv1 XOR - * IKEv2 it should be possible to move this - * magic into pluto proper and instead pass a - * simple boolean. - */ - .ikev2 = LIN(POLICY_IKEV2_PROPOSE | POLICY_IKEV2_ALLOW, wm->policy), + /* * logic needs to match pick_initiator() */ + .version = LIN(POLICY_IKEV2_ALLOW, wm->policy) ? IKEv2 : IKEv1, .alg_is_ok = ike_alg_is_ike, .pfs = LIN(POLICY_PFS, wm->policy), + .check_pfs_vs_dh = false, .warning = libreswan_log, }; - c->alg_info_ike = alg_info_ike_create_from_str(&proposal_policy, wm->ike, - err_buf, sizeof(err_buf)); + struct proposal_parser *parser = ike_proposal_parser(&proposal_policy); + c->ike_proposals.p = proposals_from_str(parser, wm->ike); - if (c->alg_info_ike == NULL) { - pexpect(err_buf[0]); /* something */ + if (c->ike_proposals.p == NULL) { + pexpect(parser->error[0]); /* something */ loglog(RC_FATAL, "Failed to add connection \"%s\": ike string error: %s", - wm->name, err_buf); + wm->name, parser->error); + free_proposal_parser(&parser); pfree(c); return; } + free_proposal_parser(&parser); - /* from here on, error returns should alg_info_free(&c->alg_info_ike->ai); */ + /* from here on, error returns should alg_info_free(&c->ike_proposals->ai); */ LSWDBGP(DBG_CRYPT | DBG_CONTROL, buf) { lswlogs(buf, "ike (phase1) algorithm values: "); - lswlog_alg_info(buf, &c->alg_info_ike->ai); + fmt_proposals(buf, c->ike_proposals.p); }; - if (c->alg_info_ike->ai.alg_info_cnt == 0) { - loglog(RC_FATAL, - "Failed to add connection \"%s\": got 0 transforms for ike=\"%s\"", - wm->name, wm->ike); - alg_info_free(&c->alg_info_ike->ai); - pfree(c); - return; - } } /* ESP or AH cipher suites (but not both) */ @@ -1607,10 +1584,7 @@ DBG(DBG_CONTROL, DBG_log("from whack: got --esp=%s", wm->esp)); - char err_buf[256] = ""; /* ??? big enough? */ - const struct proposal_policy proposal_policy = { - .ikev1 = LIN(POLICY_IKEV1_ALLOW, wm->policy), /* * logic needs to match pick_initiator() * @@ -1619,11 +1593,16 @@ * magic into pluto proper and instead pass a * simple boolean. */ - .ikev2 = LIN(POLICY_IKEV2_PROPOSE | POLICY_IKEV2_ALLOW, wm->policy), + .version = LIN(POLICY_IKEV2_ALLOW, wm->policy) ? IKEv2 : IKEv1, .alg_is_ok = kernel_alg_is_ok, .pfs = LIN(POLICY_PFS, wm->policy), + .check_pfs_vs_dh = true, .warning = libreswan_log, }; + struct proposal_parser *(*fn)(const struct proposal_policy *policy) = + (c->policy & POLICY_ENCRYPT ? esp_proposal_parser : + ah_proposal_parser); + struct proposal_parser *parser = fn(&proposal_policy); /* * We checked above that exactly one of @@ -1632,42 +1611,22 @@ * function is called (and those functions are * almost identical). */ - c->alg_info_esp = - /* function: */ - (c->policy & POLICY_ENCRYPT ? - alg_info_esp_create_from_str : - alg_info_ah_create_from_str) - /* arguments: */ - (&proposal_policy, - wm->esp, err_buf, sizeof(err_buf)); - - if (c->alg_info_esp == NULL) { + c->child_proposals.p = proposals_from_str(parser, wm->esp); + if (c->child_proposals.p == NULL) { loglog(RC_FATAL, "Failed to add connection \"%s\", esp=\"%s\" is invalid: %s", - wm->name, wm->esp, err_buf); - if (c->alg_info_ike != NULL) - alg_info_free(&c->alg_info_ike->ai); + wm->name, wm->esp, parser->error); + free_proposal_parser(&parser); pfree(c); return; } + free_proposal_parser(&parser); - /* from here on, error returns should alg_info_free(&c->alg_info_esp->ai); */ - - if (c->alg_info_esp->ai.alg_info_cnt == 0) { - loglog(RC_FATAL, - "Failed to add connection \"%s\", esp=\"%s\" contained 0 valid transforms", - wm->name, wm->esp); - if (c->alg_info_ike != NULL) - alg_info_free(&c->alg_info_ike->ai); - if (c->alg_info_esp != NULL) \ - alg_info_free(&c->alg_info_esp->ai); - pfree(c); - return; - } + /* from here on, error returns should alg_info_free(&c->child_proposals->ai); */ LSWDBGP(DBG_CONTROL, buf) { lswlogs(buf, "ESP/AH string values: "); - lswlog_alg_info(buf, &c->alg_info_esp->ai); + fmt_proposals(buf, c->child_proposals.p); }; } diff -Naur libreswan-3.27-orig/programs/pluto/connections.h libreswan-3.27/programs/pluto/connections.h --- libreswan-3.27-orig/programs/pluto/connections.h 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/connections.h 2019-02-15 16:32:28.986835407 -0500 @@ -29,6 +29,7 @@ #define CONNECTIONS_H #include "fd.h" +#include "proposals.h" /* There are two kinds of connections: * - ISAKMP connections, between hosts (for IKE communication) @@ -318,8 +319,8 @@ /* if multiple policies, next one to apply */ struct connection *policy_next; - struct alg_info_esp *alg_info_esp; /* ??? OK for AH too? */ - struct alg_info_ike *alg_info_ike; + struct ike_proposals ike_proposals; + struct child_proposals child_proposals; /* * The ALG_INFO converted to IKEv2 format. @@ -327,9 +328,23 @@ * Since they are allocated on-demand so there's no need to * worry about copying them when a connection object gets * cloned. + * + * For a child SA, two different proposals are used: + * + * - during the IKE_AUTH exchange a proposal stripped of any + * DH (it uses keying material from the IKE SA's SKSEED). + * + * - during a CREATE_CHILD_SA exchange, a mash up of the + * proposal and the IKE SA's DH algorithm. Since the IKE + * SA's DH can change, it too is saved so a rebuild can be + * triggered. + * + * XXX: has to be a better way? */ - struct ikev2_proposals *ike_proposals; - struct ikev2_proposals *esp_or_ah_proposals; + struct ikev2_proposals *v2_ike_proposals; + struct ikev2_proposals *v2_ike_auth_child_proposals; + struct ikev2_proposals *v2_create_child_proposals; + const struct oakley_group_desc *v2_create_child_proposals_default_dh; /* host_pair linkage */ struct host_pair *host_pair; diff -Naur libreswan-3.27-orig/programs/pluto/crypto.c libreswan-3.27/programs/pluto/crypto.c --- libreswan-3.27-orig/programs/pluto/crypto.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/crypto.c 2019-02-15 16:32:28.987835416 -0500 @@ -33,11 +33,12 @@ #include "state.h" #include "log.h" #include "crypto.h" -#include "alg_info.h" +#include "proposals.h" #include "ike_alg.h" #include "test_buffer.h" #include "connections.h" +#include "ike_alg_integ.h" #include "kernel_alg.h" /* @@ -47,7 +48,7 @@ */ void ike_alg_show_connection(const struct connection *c, const char *instance) { - if (c->alg_info_ike != NULL) { + if (c->ike_proposals.p != NULL) { /* * List the algorithms as found in alg_info_ike and as * will be fed into the proposal code. @@ -79,30 +80,46 @@ LSWLOG_WHACK(RC_COMMENT, buf) { lswlogf(buf, "\"%s\"%s: IKE algorithms: ", c->name, instance); - lswlog_alg_info(buf, &c->alg_info_ike->ai); + fmt_proposals(buf, c->ike_proposals.p); } } const struct state *st = state_with_serialno(c->newest_isakmp_sa); if (st != NULL) { - /* - * Convert the crypt-suite into 'struct proposal_info' - * so that the parser's print-alg code can be used. - */ - const struct proposal_info p = { - .encrypt = st->st_oakley.ta_encrypt, - .enckeylen = st->st_oakley.enckeylen, - .prf = st->st_oakley.ta_prf, - .integ = st->st_oakley.ta_integ, - .dh = st->st_oakley.ta_dh, - }; - const char *v = st->st_ikev2 ? "IKEv2" : "IKE"; LSWLOG_WHACK(RC_COMMENT, buf) { lswlogf(buf, "\"%s\"%s: %s algorithm newest: ", - c->name, instance, v); - lswlog_proposal_info(buf, &p); + c->name, instance, + "IKE"); + const struct trans_attrs *ta = &st->st_oakley; + const char *sep = ""; + if (ta->ta_encrypt != NULL) { + lswlogs(buf, sep); sep = "-"; + lswlogs(buf, ta->ta_encrypt->common.fqn); + if (ta->enckeylen != 0) { + lswlogf(buf, "_%d", ta->enckeylen); + } + } + if (ta->ta_prf != NULL) { + lswlogs(buf, sep); sep = "-"; + lswlogs(buf, ta->ta_prf->common.fqn); + } + /* XXX: should just print everything */ + if (ta->ta_integ != NULL) { + if ((ta->ta_prf == NULL) || + (encrypt_desc_is_aead(ta->ta_encrypt) && + ta->ta_integ != &ike_alg_integ_none) || + (!encrypt_desc_is_aead(ta->ta_encrypt) && + ta->ta_integ->prf != ta->ta_prf)) { + lswlogs(buf, sep); sep = "-"; + lswlogs(buf, ta->ta_integ->common.fqn); + } + } + if (ta->ta_dh != NULL) { + lswlogs(buf, sep); sep = "-"; + lswlogs(buf, ta->ta_dh->common.fqn); + } } } } diff -Naur libreswan-3.27-orig/programs/pluto/db_ops.c libreswan-3.27/programs/pluto/db_ops.c --- libreswan-3.27-orig/programs/pluto/db_ops.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/db_ops.c 2019-02-15 16:32:28.987835416 -0500 @@ -62,6 +62,7 @@ #include "defs.h" #include "state.h" #include "packet.h" +#include "proposals.h" #include "spdb.h" #include "db_ops.h" #include "log.h" diff -Naur libreswan-3.27-orig/programs/pluto/hmac.c libreswan-3.27/programs/pluto/hmac.c --- libreswan-3.27-orig/programs/pluto/hmac.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/hmac.c 2019-02-15 16:32:28.988835425 -0500 @@ -27,7 +27,7 @@ #include "constants.h" #include "defs.h" #include "crypto.h" -#include "alg_info.h" +#include "proposals.h" #include "ike_alg.h" #include diff -Naur libreswan-3.27-orig/programs/pluto/hostpair.c libreswan-3.27/programs/pluto/hostpair.c --- libreswan-3.27-orig/programs/pluto/hostpair.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/hostpair.c 2019-02-15 16:32:28.988835425 -0500 @@ -57,7 +57,7 @@ #include "log.h" #include "keys.h" #include "whack.h" -#include "alg_info.h" +#include "proposals.h" #include "spdb.h" #include "ike_alg.h" #include "kernel_alg.h" diff -Naur libreswan-3.27-orig/programs/pluto/ikev1_aggr.c libreswan-3.27/programs/pluto/ikev1_aggr.c --- libreswan-3.27-orig/programs/pluto/ikev1_aggr.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/ikev1_aggr.c 2019-02-15 16:32:28.989835435 -0500 @@ -24,7 +24,7 @@ #include "constants.h" /* for dup_any()!?! ... */ #include "lswlog.h" -#include "alg_info.h" +#include "proposals.h" #include "defs.h" #include "state.h" diff -Naur libreswan-3.27-orig/programs/pluto/ikev1.h libreswan-3.27/programs/pluto/ikev1.h --- libreswan-3.27-orig/programs/pluto/ikev1.h 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/ikev1.h 2019-02-15 16:32:28.989835435 -0500 @@ -6,11 +6,14 @@ #include "packet.h" /* for pb_stream */ #include "fd.h" +struct child_proposals; +struct ike_proposals; + /* ikev1.c */ extern void init_ikev1(void); -const struct oakley_group_desc *ikev1_quick_pfs(struct alg_info_esp *aie); +const struct oakley_group_desc *ikev1_quick_pfs(const struct child_proposals proposals); void ikev1_init_out_pbs_echo_hdr(struct msg_digest *md, bool enc, uint8_t np, pb_stream *output_stream, uint8_t *output_buffer, diff -Naur libreswan-3.27-orig/programs/pluto/ikev1_quick.c libreswan-3.27/programs/pluto/ikev1_quick.c --- libreswan-3.27-orig/programs/pluto/ikev1_quick.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/ikev1_quick.c 2019-02-15 16:32:28.990835444 -0500 @@ -79,20 +79,22 @@ #include "virtual.h" /* needs connections.h */ #include "ikev1_dpd.h" #include "pluto_x509.h" -#include "alg_info.h" +#include "proposals.h" #include "ip_address.h" #include -const struct oakley_group_desc *ikev1_quick_pfs(struct alg_info_esp *aie) +const struct oakley_group_desc *ikev1_quick_pfs(const struct child_proposals proposals) { - if (aie == NULL) { + if (proposals.p == NULL) { return NULL; } - if (aie->ai.alg_info_cnt == 0) { + struct proposal *proposal = next_proposal(proposals.p, NULL); + struct algorithm *dh = next_algorithm(proposal, PROPOSAL_dh, NULL); + if (dh == NULL) { return NULL; } - return aie->ai.proposals[0].dh; + return dh_desc(dh->desc); } /* accept_PFS_KE @@ -816,7 +818,7 @@ * use that group. * if not, fallback to old use-same-as-P1 behaviour */ - st->st_pfs_group = ikev1_quick_pfs(c->alg_info_esp); + st->st_pfs_group = ikev1_quick_pfs(c->child_proposals); /* otherwise, use the same group as during Phase 1: * since no negotiation is possible, we pick one that is * very likely supported. @@ -832,8 +834,8 @@ } lswlogf(buf, " {using isakmp#%lu msgid:%08" PRIx32 " proposal=", isakmp_sa->st_serialno, st->st_msgid); - if (st->st_connection->alg_info_esp != NULL) { - lswlog_alg_info(buf, &st->st_connection->alg_info_esp->ai); + if (st->st_connection->child_proposals.p != NULL) { + fmt_proposals(buf, st->st_connection->child_proposals.p); } else { lswlogf(buf, "defaults"); } diff -Naur libreswan-3.27-orig/programs/pluto/ikev1_spdb_struct.c libreswan-3.27/programs/pluto/ikev1_spdb_struct.c --- libreswan-3.27-orig/programs/pluto/ikev1_spdb_struct.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/ikev1_spdb_struct.c 2019-02-15 16:32:28.991835453 -0500 @@ -47,7 +47,7 @@ #include "crypto.h" #include "ikev1.h" -#include "alg_info.h" +#include "proposals.h" #include "kernel_alg.h" #include "ike_alg.h" #include "ike_alg_encrypt.h" @@ -305,17 +305,18 @@ return false; } - if (c->alg_info_esp== NULL) { + if (c->child_proposals.p == NULL) { DBGF(DBG_CONTROL, "ESP IPsec Transform verified unconditionally; no alg_info to check against"); return true; } - FOR_EACH_ESP_INFO(c->alg_info_esp, esp_info) { - if (esp_info->encrypt == ta->ta_encrypt && - (esp_info->enckeylen == 0 || - ta->enckeylen == 0 || - esp_info->enckeylen == ta->enckeylen) && - esp_info->integ == ta->ta_integ) { + FOR_EACH_PROPOSAL(c->child_proposals.p, proposal) { + struct v1_proposal algs = v1_proposal(proposal); + if (algs.encrypt == ta->ta_encrypt && + (algs.enckeylen == 0 || + ta->enckeylen == 0 || + algs.enckeylen == ta->enckeylen) && + algs.integ == ta->ta_integ) { DBG(DBG_CONTROL, DBG_log("ESP IPsec Transform verified; matches alg_info entry")); return true; @@ -351,14 +352,15 @@ ta->ta_dh->common.fqn); return false; } - if (c->alg_info_esp == NULL) { + if (c->child_proposals.p == NULL) { DBG(DBG_CONTROL, DBG_log("AH IPsec Transform verified unconditionally; no alg_info to check against")); return true; } - FOR_EACH_ESP_INFO(c->alg_info_esp, esp_info) { /* really AH */ - if (esp_info->integ == ta->ta_integ) { + FOR_EACH_PROPOSAL(c->child_proposals.p, proposal) { /* really AH */ + struct v1_proposal algs = v1_proposal(proposal); + if (algs.integ == ta->ta_integ) { DBG(DBG_CONTROL, DBG_log("ESP IPsec Transform verified; matches alg_info entry")); return true; @@ -401,12 +403,12 @@ * Aggr-Mode - Max transforms == 2 - Multiple * transforms, 1 DH group */ - revised_sadb = oakley_alg_makedb(st->st_connection->alg_info_ike, + revised_sadb = oakley_alg_makedb(st->st_connection->ike_proposals, auth_method, aggressive_mode); } else { revised_sadb = kernel_alg_makedb(st->st_connection->policy, - st->st_connection->alg_info_esp, + st->st_connection->child_proposals, TRUE); /* add IPcomp proposal if policy asks for it */ @@ -984,7 +986,7 @@ } static bool ikev1_verify_ike(const struct trans_attrs *ta, - struct alg_info_ike *alg_info_ike) + struct ike_proposals ike_proposals) { if (ta->ta_encrypt == NULL) { loglog(RC_LOG_SERIOUS, @@ -1005,7 +1007,7 @@ loglog(RC_LOG_SERIOUS, "OAKLEY proposal refused: missing DH"); return false; } - if (alg_info_ike == NULL) { + if (ike_proposals.p == NULL) { DBG(DBG_CONTROL, DBG_log("OAKLEY proposal verified unconditionally; no alg_info to check against")); return true; @@ -1016,14 +1018,14 @@ * if specified in "esp" string */ bool ealg_insecure = (ta->enckeylen < 128); - - FOR_EACH_IKE_INFO(alg_info_ike, ike_info) { - if (ike_info->encrypt == ta->ta_encrypt && - (ike_info->enckeylen == 0 || + FOR_EACH_PROPOSAL(ike_proposals.p, proposal) { + struct v1_proposal algs = v1_proposal(proposal); + if (algs.encrypt == ta->ta_encrypt && + (algs.enckeylen == 0 || ta->enckeylen == 0 || - ike_info->enckeylen == ta->enckeylen) && - ike_info->prf == ta->ta_prf && - ike_info->dh == ta->ta_dh) { + algs.enckeylen == ta->enckeylen) && + algs.prf == ta->ta_prf && + algs.dh == ta->ta_dh) { if (ealg_insecure) { loglog(RC_LOG_SERIOUS, "You should NOT use insecure/broken IKE algorithms (%s)!", @@ -1522,7 +1524,7 @@ } /* * check if this keylen is compatible - * with specified alg_info_ike. + * with specified ike_proposals. */ if (!encrypt_has_key_bit_length(ta.ta_encrypt, val)) { ugh = "peer proposed key_len not valid for encrypt algo setup specified"; @@ -1584,9 +1586,9 @@ } /* - * ML: at last check for allowed transforms in alg_info_ike + * ML: at last check for allowed transforms in ike_proposals */ - if (!ikev1_verify_ike(&ta, c->alg_info_ike)) { + if (!ikev1_verify_ike(&ta, c->ike_proposals)) { /* * already logged; UGH acts as a skip * rest of checks flag @@ -1715,7 +1717,7 @@ const struct connection *c = st->st_connection; /* - * Construct the proposals by combining ALG_INFO_IKE with the + * Construct the proposals by combining IKE_PROPOSALS with the * AUTH (proof of identity) extracted from the aggressive mode * SADB. As if by magic, attrs[2] is always the * authentication method. @@ -1733,7 +1735,7 @@ * Max transforms == 2 - Multiple transforms, 1 DH * group */ - revised_sadb = oakley_alg_makedb(c->alg_info_ike, + revised_sadb = oakley_alg_makedb(c->ike_proposals, auth_method, TRUE); } diff -Naur libreswan-3.27-orig/programs/pluto/ikev2.c libreswan-3.27/programs/pluto/ikev2.c --- libreswan-3.27-orig/programs/pluto/ikev2.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/ikev2.c 2019-02-15 16:32:28.993835472 -0500 @@ -68,7 +68,7 @@ #include "vendor.h" #include "ip_address.h" #include "ikev2_send.h" -#include "alg_info.h" /* for ike_info / esp_info */ +#include "proposals.h" /* for ike_info / esp_info */ #include "ietf_constants.h" diff -Naur libreswan-3.27-orig/programs/pluto/ikev2_crypto.c libreswan-3.27/programs/pluto/ikev2_crypto.c --- libreswan-3.27-orig/programs/pluto/ikev2_crypto.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/ikev2_crypto.c 2019-02-15 16:32:28.993835472 -0500 @@ -52,7 +52,7 @@ #include "ikev2.h" #include "ikev2_prf.h" #include "ike_alg.h" -#include "alg_info.h" +#include "proposals.h" #include "kernel_alg.h" #include "crypt_symkey.h" #include "ikev2_prf.h" diff -Naur libreswan-3.27-orig/programs/pluto/ikev2.h libreswan-3.27/programs/pluto/ikev2.h --- libreswan-3.27-orig/programs/pluto/ikev2.h 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/ikev2.h 2019-02-15 16:32:28.994835481 -0500 @@ -97,11 +97,27 @@ void free_ikev2_proposal(struct ikev2_proposal **proposal); void free_ikev2_proposals(struct ikev2_proposals **proposals); -void ikev2_need_ike_proposals(struct connection *c, const char *why); +/* + * On-demand, generate proposals for either the IKE SA or the CHILD + * SA. + * + * For CHILD SAs, two different proposal suites are used: during the + * IKE_AUTH exchange a stripped down proposal that excludes DH; and + * during the CREATE_CHILD_SA exchange DH a mashed up proposal that + * can include the IKE SA's latest DH. + * + * This is done on-demand as, only at the point where the IKE or CHILD + * SA is being instantiated, is it clear what proposals are needed. + * For instance, when a CHILD SA shares an existing IKE SA, the CHILD + * won't need IKE proposals but will need the IKE SA's DH. + * + * XXX: Should the CREATE CHILD SA proposals be stored in the state? + */ -void ikev2_need_esp_or_ah_proposals(struct connection *c, - const char *why, - const struct oakley_group_desc *default_dh); +struct ikev2_proposals *get_v2_ike_proposals(struct connection *c, const char *why); +struct ikev2_proposals *get_v2_ike_auth_child_proposals(struct connection *c, const char *why); +struct ikev2_proposals *get_v2_create_child_proposals(struct connection *c, const char *why, + const struct oakley_group_desc *default_dh); bool ikev2_emit_sa_proposal(pb_stream *pbs, const struct ikev2_proposal *proposal, diff -Naur libreswan-3.27-orig/programs/pluto/ikev2_parent.c libreswan-3.27/programs/pluto/ikev2_parent.c --- libreswan-3.27-orig/programs/pluto/ikev2_parent.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/ikev2_parent.c 2019-02-15 16:32:28.996835500 -0500 @@ -67,7 +67,7 @@ #include "pending.h" #include "kernel.h" #include "nat_traversal.h" -#include "alg_info.h" /* for ike_info / esp_info */ +#include "proposals.h" /* for ike_info / esp_info */ #include "key.h" /* for SECKEY_DestroyPublicKey */ #include "vendor.h" #include "crypt_hash.h" @@ -848,8 +848,9 @@ * Initialize st->st_oakley, including the group number. * Grab the DH group from the first configured proposal and build KE. */ - ikev2_need_ike_proposals(c, "IKE SA initiator selecting KE"); - st->st_oakley.ta_dh = ikev2_proposals_first_dh(c->ike_proposals); + struct ikev2_proposals *ike_proposals = + get_v2_ike_proposals(c, "IKE SA initiator selecting KE"); + st->st_oakley.ta_dh = ikev2_proposals_first_dh(ike_proposals); if (st->st_oakley.ta_dh == NULL) { libreswan_log("proposals do not contain a valid DH"); delete_state(st); /* pops state? */ @@ -991,7 +992,8 @@ } /* SA out */ { - ikev2_need_ike_proposals(c, "IKE SA initiator emitting local proposals"); + struct ikev2_proposals *ike_proposals = + get_v2_ike_proposals(c, "IKE SA initiator emitting local proposals"); /* * Since this is an initial IKE exchange, the SPI is * emitted as is part of the packet header and not the @@ -999,7 +1001,7 @@ */ u_char *sa_start = rbody.cur; bool ret = ikev2_emit_sa_proposals(&rbody, - c->ike_proposals, + ike_proposals, (chunk_t*)NULL); if (!ret) { libreswan_log("outsa fail"); @@ -1328,7 +1330,8 @@ } /* Get the proposals ready. */ - ikev2_need_ike_proposals(c, "IKE SA responder matching remote proposals"); + struct ikev2_proposals *ike_proposals = + get_v2_ike_proposals(c, "IKE SA responder matching remote proposals"); /* * Select the proposal. @@ -1342,7 +1345,7 @@ /*expect_accepted*/ FALSE, LIN(POLICY_OPPORTUNISTIC, c->policy), &accepted_ike_proposal, - c->ike_proposals); + ike_proposals); if (ret != STF_OK) return ret; @@ -1812,9 +1815,10 @@ pstats(invalidke_recv_s, sg.sg_group); pstats(invalidke_recv_u, st->st_oakley.ta_dh->group); - ikev2_need_ike_proposals(c, "IKE SA initiator validating remote's suggested KE"); + struct ikev2_proposals *ike_proposals = + get_v2_ike_proposals(c, "IKE SA initiator validating remote's suggested KE"); - if (ikev2_proposals_include_modp(c->ike_proposals, sg.sg_group)) { + if (ikev2_proposals_include_modp(ike_proposals, sg.sg_group)) { DBG(DBG_CONTROLMORE, DBG_log("Suggested modp group is acceptable")); /* * Since there must be a group object @@ -2081,7 +2085,9 @@ /* SA body in and out */ struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_v2SA]; - ikev2_need_ike_proposals(c, "IKE SA initiator accepting remote proposal"); + struct ikev2_proposals *ike_proposals = + get_v2_ike_proposals(c, "IKE SA initiator accepting remote proposal"); + stf_status ret = ikev2_process_sa_payload("IKE initiator (accepting)", &sa_pd->pbs, @@ -2090,7 +2096,7 @@ /*expect_accepted*/ TRUE, LIN(POLICY_OPPORTUNISTIC, c->policy), &st->st_accepted_ike_proposal, - c->ike_proposals); + ike_proposals); if (ret != STF_OK) { DBG(DBG_CONTROLMORE, DBG_log("ikev2_parse_parent_sa_body() failed in ikev2_parent_inR1outI2()")); return ret; @@ -3564,17 +3570,13 @@ sizeof(proto_info->our_spi)); /* - * UNSET_GROUP means strip DH from the proposal. A - * CHILD_SA established during an AUTH exchange does + * A CHILD_SA established during an AUTH exchange does * not propose DH - the IKE SA's SKEYSEED is always * used. */ - free_ikev2_proposals(&cc->esp_or_ah_proposals); - ikev2_need_esp_or_ah_proposals(cc, - "IKE SA initiator emitting ESP/AH proposals", - &unset_group); - - if (!ikev2_emit_sa_proposals(&e_pbs_cipher, cc->esp_or_ah_proposals, + struct ikev2_proposals *child_proposals = + get_v2_ike_auth_child_proposals(cc, "IKE SA initiator emitting ESP/AH proposals"); + if (!ikev2_emit_sa_proposals(&e_pbs_cipher, child_proposals, &local_spi)) return STF_INTERNAL_ERROR; @@ -4374,31 +4376,25 @@ stf_status ret; char *what; - const struct oakley_group_desc *default_dh; + struct ikev2_proposals *child_proposals; if (isa_xchg == ISAKMP_v2_CREATE_CHILD_SA) { if (st->st_state == STATE_V2_CREATE_I) { what = "ESP/AH initiator accepting remote proposal"; } else { what = "ESP/AH responder matching remote proposals"; } - default_dh = (c->policy & POLICY_PFS) != LEMPTY + const struct oakley_group_desc *default_dh = (c->policy & POLICY_PFS) != LEMPTY ? ike->sa.st_oakley.ta_dh : &ike_alg_dh_none; + child_proposals = get_v2_create_child_proposals(c, what, default_dh); } else if (expect_accepted) { - what = "IKE SA initiator accepting remote ESP/AH proposal"; - default_dh = &unset_group; /* no DH */ + what = "IKE_AUTH initiator accepting remote ESP/AH proposal"; + child_proposals = get_v2_ike_auth_child_proposals(c, what); } else { - what = "IKE SA responder matching remote ESP/AH proposals"; - default_dh = &unset_group; /* no DH */ - } - - if (!expect_accepted) { - /* preparing to initiate or parse a request flush old ones */ - free_ikev2_proposals(&c->esp_or_ah_proposals); + what = "IKE_AUTH responder matching remote ESP/AH proposals"; + child_proposals = get_v2_ike_auth_child_proposals(c, what); } - ikev2_need_esp_or_ah_proposals(c, what, default_dh); - ret = ikev2_process_sa_payload(what, &sa_pd->pbs, /*expect_ike*/ FALSE, @@ -4406,7 +4402,7 @@ expect_accepted, LIN(POLICY_OPPORTUNISTIC, c->policy), &st->st_accepted_esp_or_ah_proposal, - c->esp_or_ah_proposals); + child_proposals); if (ret != STF_OK) { LSWLOG_RC(RC_LOG_SERIOUS, buf) { @@ -5217,8 +5213,8 @@ chunk_t local_spi; setchunk(local_spi, (uint8_t*)&proto_info->our_spi, sizeof(proto_info->our_spi)); - - if (!ikev2_emit_sa_proposals(outpbs, cc->esp_or_ah_proposals, + passert(cc->v2_create_child_proposals != NULL); + if (!ikev2_emit_sa_proposals(outpbs, cc->v2_create_child_proposals, &local_spi)) return STF_INTERNAL_ERROR; @@ -5312,12 +5308,11 @@ sizeof(st->st_icookie)); local_nonce = st->st_ni; - /* ??? why do we need to free the previous proposals? */ - free_ikev2_proposals(&c->ike_proposals); - ikev2_need_ike_proposals(c, "IKE SA initiating rekey"); + struct ikev2_proposals *ike_proposals = + get_v2_ike_proposals(c, "IKE SA initiating rekey"); /* send v2 IKE SAs*/ - if (!ikev2_emit_sa_proposals(outpbs, c->ike_proposals, &local_spi)) { + if (!ikev2_emit_sa_proposals(outpbs, ike_proposals, &local_spi)) { libreswan_log("outsa fail"); DBG(DBG_CONTROL, DBG_log("problem emitting connection ike proposals in CREATE_CHILD_SA")); return STF_INTERNAL_ERROR; @@ -5379,7 +5374,8 @@ struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_v2SA]; /* Get the proposals ready. */ - ikev2_need_ike_proposals(c, "IKE SA accept response to rekey"); + struct ikev2_proposals *ike_proposals = + get_v2_ike_proposals(c, "IKE SA accept response to rekey"); stf_status ret = ikev2_process_sa_payload("IKE initiator (accepting)", &sa_pd->pbs, @@ -5388,7 +5384,7 @@ /*expect_accepted*/ TRUE, LIN(POLICY_OPPORTUNISTIC, c->policy), &st->st_accepted_ike_proposal, - c->ike_proposals); + ike_proposals); if (ret != STF_OK) { DBG(DBG_CONTROLMORE, DBG_log("failed to accept IKE SA, REKEY, response, in process_ike_rekey_sa_pl_response")); return ret; @@ -5424,7 +5420,8 @@ struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_v2SA]; /* Get the proposals ready. */ - ikev2_need_ike_proposals(c, "IKE SA responding to rekey"); + struct ikev2_proposals *ike_proposals = + get_v2_ike_proposals(c, "IKE SA responding to rekey"); struct ikev2_proposal *accepted_ike_proposal = NULL; stf_status ret = ikev2_process_sa_payload("IKE Rekey responder child", @@ -5434,7 +5431,7 @@ /*expect_accepted*/ FALSE, LIN(POLICY_OPPORTUNISTIC, c->policy), &accepted_ike_proposal, - c->ike_proposals); + ike_proposals); if (ret != STF_OK) return ret; @@ -6677,21 +6674,17 @@ if (sa_type == IPSEC_SA) { const struct state *rst = state_with_serialno(p->replacing); - /* - * Because the proposal generated during AUTH won't contain DH, - * always force the proposal to be re-generated here. Not the - * most efficient, fix probably means moving the proposals to - * the state object. - */ - free_ikev2_proposals(&c->esp_or_ah_proposals); const struct oakley_group_desc *default_dh = c->policy & POLICY_PFS ? ike->sa.st_oakley.ta_dh : NULL; - ikev2_need_esp_or_ah_proposals(c, - "ESP/AH initiator emitting proposals", - default_dh); + struct ikev2_proposals *child_proposals = + get_v2_create_child_proposals(c, + "ESP/AH initiator emitting proposals", + default_dh); + /* see ikev2_child_add_ipsec_payloads */ + passert(c->v2_create_child_proposals != NULL); - st->st_pfs_group = ikev2_proposals_first_dh(c->esp_or_ah_proposals); + st->st_pfs_group = ikev2_proposals_first_dh(child_proposals); DBG(DBG_CONTROLMORE, { const char *pfsgroupname = st->st_pfs_group == NULL ? diff -Naur libreswan-3.27-orig/programs/pluto/ikev2_spdb_struct.c libreswan-3.27/programs/pluto/ikev2_spdb_struct.c --- libreswan-3.27-orig/programs/pluto/ikev2_spdb_struct.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/ikev2_spdb_struct.c 2019-02-15 16:32:28.998835518 -0500 @@ -51,7 +51,7 @@ #include "crypto.h" -#include "alg_info.h" +#include "proposals.h" #include "kernel_alg.h" #include "ike_alg.h" #include "ike_alg_integ.h" @@ -264,7 +264,7 @@ * * PROPNUM is an int. */ -#define FOR_EACH_PROPOSAL(PROPNUM, PROPOSAL, PROPOSALS) \ +#define FOR_EACH_V2_PROPOSAL(PROPNUM, PROPOSAL, PROPOSALS) \ for ((PROPNUM) = 1, \ (PROPOSAL) = &(PROPOSALS)->proposal[(PROPNUM)]; \ (PROPNUM) < (PROPOSALS)->roof; \ @@ -276,7 +276,7 @@ * * PROPNUM, BASE, BOUND are all ints. */ -#define FOR_EACH_PROPOSAL_IN_RANGE(PROPNUM, PROPOSAL, PROPOSALS, BASE, BOUND) \ +#define FOR_EACH_V2_PROPOSAL_IN_RANGE(PROPNUM, PROPOSAL, PROPOSALS, BASE, BOUND) \ for ((PROPNUM) = ((BASE) > 0 ? (BASE) : 1), \ (PROPOSAL) = &(PROPOSALS)->proposal[(PROPNUM)]; \ (PROPNUM) < (BOUND) && (PROPNUM) < (PROPOSALS)->roof; \ @@ -395,7 +395,7 @@ const char *proposal_sep = ""; int propnum; const struct ikev2_proposal *proposal; - FOR_EACH_PROPOSAL(propnum, proposal, proposals) { + FOR_EACH_V2_PROPOSAL(propnum, proposal, proposals) { lswlogs(buf, proposal_sep); proposal_sep = " "; print_proposal(buf, propnum, proposal); @@ -443,8 +443,8 @@ { int local_propnum; const struct ikev2_proposal *local_proposal; - FOR_EACH_PROPOSAL_IN_RANGE(local_propnum, local_proposal, local_proposals, - local_propnum_base, local_propnum_bound) { + FOR_EACH_V2_PROPOSAL_IN_RANGE(local_propnum, local_proposal, local_proposals, + local_propnum_base, local_propnum_bound) { struct ikev2_proposal_match *matching_local_proposal = &matching_local_proposals[local_propnum]; /* clear matched */ matching_local_proposal->matched_transform_types = LEMPTY; @@ -579,8 +579,8 @@ */ int local_propnum; struct ikev2_proposal *local_proposal; - FOR_EACH_PROPOSAL_IN_RANGE(local_propnum, local_proposal, local_proposals, - local_propnum_base, local_propnum_bound) { + FOR_EACH_V2_PROPOSAL_IN_RANGE(local_propnum, local_proposal, local_proposals, + local_propnum_base, local_propnum_bound) { if (local_proposal->protoid == remote_protoid) { /* * Search the proposal for transforms of this @@ -680,8 +680,8 @@ int local_propnum; struct ikev2_proposal *local_proposal; - FOR_EACH_PROPOSAL_IN_RANGE(local_propnum, local_proposal, local_proposals, - local_propnum_base, local_propnum_bound) { + FOR_EACH_V2_PROPOSAL_IN_RANGE(local_propnum, local_proposal, local_proposals, + local_propnum_base, local_propnum_bound) { struct ikev2_proposal_match *matching_local_proposal = &matching_local_proposals[local_propnum]; LSWDBGP(DBG_CONTROLMORE, log) { lswlogf(log, "comparing remote proposal %u containing ", @@ -834,7 +834,7 @@ { int local_propnum; struct ikev2_proposal *local_proposal; - FOR_EACH_PROPOSAL(local_propnum, local_proposal, local_proposals) { + FOR_EACH_V2_PROPOSAL(local_propnum, local_proposal, local_proposals) { struct ikev2_proposal_match *matching_local_proposal = &matching_local_proposals[local_propnum]; enum ikev2_trans_type type; struct ikev2_transforms *local_transforms; @@ -1156,7 +1156,7 @@ * * Must be freed by this function. */ - stf_status status; + stf_status status = STF_FAIL; /* initialized just to silence gcc -Og */ LSWBUF(remote_print_buf) { int matching_local_propnum = ikev2_process_proposals(sa_payload, expect_ike, expect_spi, @@ -1448,7 +1448,7 @@ int propnum; const struct ikev2_proposal *proposal; - FOR_EACH_PROPOSAL(propnum, proposal, proposals) { + FOR_EACH_V2_PROPOSAL(propnum, proposal, proposals) { if (!emit_proposal(&sa_pbs, proposal, propnum, local_spi, (propnum < proposals->roof - 1 ? v2_PROPOSAL_NON_LAST @@ -1804,9 +1804,9 @@ return TRUE; } -static struct ikev2_proposal *ikev2_proposal_from_proposal_info(const struct proposal_info *info, +static struct ikev2_proposal *ikev2_proposal_from_proposal_info(const struct proposal *proposal, enum ikev2_sec_proto_id protoid, - struct ikev2_proposals *proposals, + struct ikev2_proposals *v2_proposals, const struct oakley_group_desc *default_dh) { /* @@ -1814,19 +1814,19 @@ * contain partially constructed stuff from an earlier * iteration). */ - struct ikev2_proposal *proposal = &proposals->proposal[proposals->roof]; - *proposal = (struct ikev2_proposal) { + struct ikev2_proposal *v2_proposal = &v2_proposals->proposal[v2_proposals->roof]; + *v2_proposal = (struct ikev2_proposal) { .protoid = protoid, - .propnum = proposals->roof, + .propnum = v2_proposals->roof, }; /* * Encryption. */ - const struct encrypt_desc *encrypt = info->encrypt; - if (encrypt != NULL) { - if (!append_encrypt_transform(proposal, encrypt, - info->enckeylen)) { + FOR_EACH_ALGORITHM(proposal, encrypt, alg) { + const struct encrypt_desc *encrypt = encrypt_desc(alg->desc); + if (!append_encrypt_transform(v2_proposal, encrypt, + alg->enckeylen)) { return NULL; } } @@ -1834,22 +1834,22 @@ /* * PRF. */ - const struct prf_desc *prf = info->prf; - if (prf != NULL) { - append_transform(proposal, IKEv2_TRANS_TYPE_PRF, + FOR_EACH_ALGORITHM(proposal, prf, alg) { + const struct prf_desc *prf = prf_desc(alg->desc); + append_transform(v2_proposal, IKEv2_TRANS_TYPE_PRF, prf->common.id[IKEv2_ALG_ID], 0); } /* * Integrity. */ - const struct integ_desc *integ = info->integ; - if (integ != NULL) { + FOR_EACH_ALGORITHM(proposal, integ, alg) { + const struct integ_desc *integ = integ_desc(alg->desc); /* * While INTEG=NONE is included in the proposal it * omitted when emitted. */ - append_transform(proposal, IKEv2_TRANS_TYPE_INTEG, + append_transform(v2_proposal, IKEv2_TRANS_TYPE_INTEG, integ->common.id[IKEv2_ALG_ID], 0); } @@ -1860,20 +1860,25 @@ * happens during the AUTH exchange). Otherwise use either * the proposed or default DH. */ - const struct oakley_group_desc *dh = - default_dh == &unset_group ? &ike_alg_dh_none - : info->dh != NULL ? info->dh - : default_dh; - if (dh != NULL) { - /* - * WHILE DH=NONE is included in the proposal it is - * omitted when emitted. - */ - append_transform(proposal, IKEv2_TRANS_TYPE_DH, - dh->common.id[IKEv2_ALG_ID], 0); + if (default_dh == &unset_group) { + append_transform(v2_proposal, IKEv2_TRANS_TYPE_DH, + ike_alg_dh_none.common.id[IKEv2_ALG_ID], 0); + } else if (next_algorithm(proposal, PROPOSAL_dh, NULL) != NULL) { + FOR_EACH_ALGORITHM(proposal, dh, alg) { + const struct oakley_group_desc *dh = dh_desc(alg->desc); + /* + * WHILE DH=NONE is included in the proposal it is + * omitted when emitted. + */ + append_transform(v2_proposal, IKEv2_TRANS_TYPE_DH, + dh->common.id[IKEv2_ALG_ID], 0); + } + } else if (default_dh != NULL) { + append_transform(v2_proposal, IKEv2_TRANS_TYPE_DH, + default_dh->common.id[IKEv2_ALG_ID], 0); } - return proposal; + return v2_proposal; } /* @@ -1993,67 +1998,73 @@ }; /* - * Ensure c->ike_proposals is filled in. If not, build it. - * - * ??? if c->ike_proposals was set for v1 we won't change it. + * On-demand compute and return the IKE proposals for the connection. * - * WARNING: alg_info_ike is IKEv1 + * If the default alg_info_ike includes unknown algorithms those get + * dropped, which can lead to no proposals. * - * If alg_info_ike includes unknown algorithms those get dropped, - * which can lead to no proposals. - * c->ike_proposals will not be NULL (see passert). + * Never returns NULL (see passert). */ -void ikev2_need_ike_proposals(struct connection *c, const char *why) { - if (c->ike_proposals != NULL) { - DBGF(DBG_CONTROL, "already constructed local IKE proposals for connection %s (%s)", - c->name, why); - return; +struct ikev2_proposals *get_v2_ike_proposals(struct connection *c, const char *why) +{ + if (c->v2_ike_proposals != NULL) { + LSWDBGP(DBG_CONTROL, buf) { + lswlogf(buf, "using existing local IKE proposals for connection %s (%s): ", + c->name, why); + print_proposals(buf, c->v2_ike_proposals); + } + return c->v2_ike_proposals; } const char *notes; - if (c->alg_info_ike == NULL) { + if (c->ike_proposals.p == NULL) { DBGF(DBG_CONTROL, "selecting default constructed local IKE proposals for connection %s (%s)", c->name, why); - c->ike_proposals = &default_ikev2_ike_proposals; + c->v2_ike_proposals = &default_ikev2_ike_proposals; notes = " (default)"; } else { DBGF(DBG_CONTROL, "constructing local IKE proposals for %s (%s)", c->name, why); - struct ikev2_proposals *proposals = alloc_thing(struct ikev2_proposals, "proposals"); - int proposals_roof = c->alg_info_ike->ai.alg_info_cnt + 1; - proposals->proposal = alloc_things(struct ikev2_proposal, proposals_roof, "propsal"); - proposals->on_heap = TRUE; - proposals->roof = 1; + struct ikev2_proposals *v2_proposals = alloc_thing(struct ikev2_proposals, + "proposals"); + /* +1 as proposal[0] is empty */ + int v2_proposals_roof = nr_proposals(c->ike_proposals.p) + 1; + v2_proposals->proposal = alloc_things(struct ikev2_proposal, + v2_proposals_roof, "propsal"); + v2_proposals->on_heap = TRUE; + v2_proposals->roof = 1; - FOR_EACH_IKE_INFO(c->alg_info_ike, ike_info) { + FOR_EACH_PROPOSAL(c->ike_proposals.p, ike_info) { LSWDBGP(DBG_CONTROL, buf) { lswlogs(buf, "converting ike_info "); - lswlog_proposal_info(buf, ike_info); + fmt_proposal(buf, ike_info); lswlogs(buf, " to ikev2 ..."); } - passert(proposals->roof < proposals_roof); - struct ikev2_proposal *proposal = - ikev2_proposal_from_proposal_info(ike_info, IKEv2_SEC_PROTO_IKE, - proposals, NULL); - if (proposal != NULL) { + passert(v2_proposals->roof < v2_proposals_roof); + struct ikev2_proposal *v2_proposal = + ikev2_proposal_from_proposal_info(ike_info, + IKEv2_SEC_PROTO_IKE, + v2_proposals, NULL); + if (v2_proposal != NULL) { DBG(DBG_CONTROL, - DBG_log_ikev2_proposal("... ", proposal)); - proposals->roof++; + DBG_log_ikev2_proposal("... ", v2_proposal)); + v2_proposals->roof++; } } - c->ike_proposals = proposals; + c->v2_ike_proposals = v2_proposals; notes = ""; } - LSWLOG(buf) { + LSWLOG_CONNECTION(c, buf) { lswlogf(buf, "constructed local IKE proposals for %s (%s): ", c->name, why); - print_proposals(buf, c->ike_proposals); + print_proposals(buf, c->v2_ike_proposals); lswlogs(buf, notes); } - passert(c->ike_proposals != NULL); + passert(c->v2_ike_proposals != NULL); + return c->v2_ike_proposals; } static struct ikev2_proposal default_ikev2_esp_proposal_missing_esn[] = { @@ -2143,19 +2154,23 @@ } } -void ikev2_need_esp_or_ah_proposals(struct connection *c, - const char *why, - const struct oakley_group_desc *default_dh) +static struct ikev2_proposals *get_v2_child_proposals(struct ikev2_proposals **child_proposals, + struct connection *c, + const char *why, + const struct oakley_group_desc *default_dh) { - if (c->esp_or_ah_proposals != NULL) { - DBGF(DBG_CONTROL, "already constructed local ESP/AH proposals for %s (%s)", - c->name, why); - return; + if (*child_proposals != NULL) { + LSWDBGP(DBG_CONTROL, buf) { + lswlogf(buf, "using existing local ESP/AH proposals for %s (%s): ", + c->name, why); + print_proposals(buf, *child_proposals); + } + return *child_proposals; } const char *notes; - if (c->alg_info_esp == NULL) { - DBGF(DBG_CONTROL, "selecting default construvted local ESP/AH proposals for %s (%s)", + if (c->child_proposals.p == NULL) { + DBGF(DBG_CONTROL, "selecting default local ESP/AH proposals for %s (%s)", c->name, why); lset_t esp_ah = c->policy & (POLICY_ENCRYPT | POLICY_AUTHENTICATE); struct ikev2_proposals *default_proposals_missing_esn; @@ -2186,38 +2201,38 @@ /* * Clone the default proposal and add the missing ESN. */ - struct ikev2_proposals *proposals = alloc_thing(struct ikev2_proposals, - "cloned ESP/AH proposals"); - proposals->on_heap = TRUE; - proposals->roof = default_proposals_missing_esn->roof; + struct ikev2_proposals *v2_proposals = alloc_thing(struct ikev2_proposals, + "cloned ESP/AH proposals"); + v2_proposals->on_heap = TRUE; + v2_proposals->roof = default_proposals_missing_esn->roof; if (add_empty_msdh_duplicates) { /* add space for duplicates, minus the empty first proposal */ - proposals->roof += default_proposals_missing_esn->roof - 1; + v2_proposals->roof += default_proposals_missing_esn->roof - 1; } - proposals->proposal = alloc_things(struct ikev2_proposal, proposals->roof, - "ESP/AH proposals"); - memcpy(proposals->proposal, default_proposals_missing_esn->proposal, - sizeof(proposals->proposal[0]) * default_proposals_missing_esn->roof); + v2_proposals->proposal = alloc_things(struct ikev2_proposal, v2_proposals->roof, + "ESP/AH proposals"); + memcpy(v2_proposals->proposal, default_proposals_missing_esn->proposal, + sizeof(v2_proposals->proposal[0]) * default_proposals_missing_esn->roof); if (add_empty_msdh_duplicates) { /* * Append duplicates but discarding * proposal[0] which is filler. */ - memcpy(proposals->proposal + default_proposals_missing_esn->roof, + memcpy(v2_proposals->proposal + default_proposals_missing_esn->roof, default_proposals_missing_esn->proposal + 1, /* skip "0" */ - sizeof(proposals->proposal[0]) * (default_proposals_missing_esn->roof - 1)); + sizeof(v2_proposals->proposal[0]) * (default_proposals_missing_esn->roof - 1)); } int propnum; - struct ikev2_proposal *proposal; - FOR_EACH_PROPOSAL(propnum, proposal, proposals) { - add_esn_transforms(proposal, c->policy); + struct ikev2_proposal *v2_proposal; + FOR_EACH_V2_PROPOSAL(propnum, v2_proposal, v2_proposals) { + add_esn_transforms(v2_proposal, c->policy); } if (default_dh != NULL && default_dh != &unset_group) { DBGF(DBG_CONTROL, "adding dh %s to default proposals", default_dh->common.name); - FOR_EACH_PROPOSAL(propnum, proposal, proposals) { - append_transform(proposal, + FOR_EACH_V2_PROPOSAL(propnum, v2_proposal, v2_proposals) { + append_transform(v2_proposal, IKEv2_TRANS_TYPE_DH, default_dh->group, 0); if (propnum >= default_proposals_missing_esn->roof) @@ -2225,7 +2240,7 @@ break; } } - c->esp_or_ah_proposals = proposals; + *child_proposals = v2_proposals; notes = " (default)"; } else { LSWDBGP(DBG_CONTROL, buf) { @@ -2250,17 +2265,18 @@ bool add_empty_msdh_duplicates = (c->policy & POLICY_MSDH_DOWNGRADE) && default_dh != &unset_group; - struct ikev2_proposals *proposals = alloc_thing(struct ikev2_proposals, - "ESP/AH proposals"); - int proposals_roof = c->alg_info_esp->ai.alg_info_cnt + 1; + struct ikev2_proposals *v2_proposals = alloc_thing(struct ikev2_proposals, + "ESP/AH proposals"); + /* proposal[0] is empty so +1 */ + int v2_proposals_roof = nr_proposals(c->child_proposals.p) + 1; if (add_empty_msdh_duplicates) { - /* make space for everything duplicated */ - proposals_roof += c->alg_info_esp->ai.alg_info_cnt; + /* make space for everything duplicated; note +1 above */ + v2_proposals_roof = v2_proposals_roof * 2 - 1; } - proposals->proposal = alloc_things(struct ikev2_proposal, proposals_roof, - "ESP/AH proposal"); - proposals->on_heap = TRUE; - proposals->roof = 1; + v2_proposals->proposal = alloc_things(struct ikev2_proposal, v2_proposals_roof, + "ESP/AH proposal"); + v2_proposals->on_heap = TRUE; + v2_proposals->roof = 1; enum ikev2_sec_proto_id protoid; switch (c->policy & (POLICY_ENCRYPT | POLICY_AUTHENTICATE)) { @@ -2275,10 +2291,10 @@ } for (int dup = 0; dup < (add_empty_msdh_duplicates ? 2 : 1); dup++) { - FOR_EACH_ESP_INFO(c->alg_info_esp, esp_info) { + FOR_EACH_PROPOSAL(c->child_proposals.p, esp_info) { LSWDBGP(DBG_CONTROL, log) { lswlogf(log, "converting proposal "); - lswlog_proposal_info(log, esp_info); + fmt_proposal(log, esp_info); lswlogf(log, " to ikev2 ..."); } @@ -2286,37 +2302,94 @@ * Get the next proposal with the * basics filled in. */ - passert(proposals->roof < proposals_roof); - if (dup && default_dh == NULL && esp_info->dh == NULL) { + passert(v2_proposals->roof < v2_proposals_roof); + if (dup && default_dh == NULL && + next_algorithm(esp_info, PROPOSAL_dh, NULL) == NULL) { /* * First pass didn't include DH. */ continue; } - struct ikev2_proposal *proposal = - ikev2_proposal_from_proposal_info(esp_info, protoid, - proposals, + struct ikev2_proposal *v2_proposal = + ikev2_proposal_from_proposal_info(esp_info, + protoid, + v2_proposals, dup ? &unset_group : default_dh); - if (proposal != NULL) { - add_esn_transforms(proposal, c->policy); + if (v2_proposal != NULL) { + add_esn_transforms(v2_proposal, c->policy); DBG(DBG_CONTROL, - DBG_log_ikev2_proposal("... ", proposal)); - proposals->roof++; + DBG_log_ikev2_proposal("... ", v2_proposal)); + v2_proposals->roof++; } } } - c->esp_or_ah_proposals = proposals; + *child_proposals = v2_proposals; notes = ""; } - LSWLOG(buf) { + LSWLOG_CONNECTION(c, buf) { lswlogf(buf, "constructed local ESP/AH proposals for %s (%s): ", c->name, why); - print_proposals(buf, c->esp_or_ah_proposals); + print_proposals(buf, *child_proposals); lswlogs(buf, notes); } - passert(c->esp_or_ah_proposals != NULL); + passert(*child_proposals != NULL); + return *child_proposals; +} + +/* + * If needed, generate the proposals for a CHILD SA being created + * during the IKE_AUTH exchange. + * + * Since a CHILD_SA established during an IKE_AUTH exchange does not + * propose DH (keying material is taken from the IKE SA's SKEYSEED), + * DH is stripped from the proposals. + * + * Since only things that affect this proposal suite are the + * connection's .policy bits and the contents .child_proposals, and + * modifiying those triggers the creation of a new connection (true?), + * the connection can be cached. + */ + +struct ikev2_proposals *get_v2_ike_auth_child_proposals(struct connection *c, const char *why) +{ + /* UNSET_GROUP means strip DH from the proposal. */ + return get_v2_child_proposals(&c->v2_ike_auth_child_proposals, c, + why, &unset_group); +} + +/* + * If needed, generate the proposals for a CHILD SA being created (or + * re-keyed) during a CREATE_CHILD_SA exchange. + * + * If the proposals do not include DH, and PFS is enabled, then the + * DEFAULT_DH (DH used by the IKE SA) is added to all proposals. + * + * XXX: + * + * This means that the CHILD SA's proposal suite will change depending + * on what DH is negotiated by the IKE SA! Hence the need to save the + * DEFAULT_DH and check for change. It should probably be storing the + * proposal in the state. + * + * Horrible. + */ +struct ikev2_proposals *get_v2_create_child_proposals(struct connection *c, const char *why, + const struct oakley_group_desc *default_dh) +{ + if (c->v2_create_child_proposals_default_dh != default_dh) { + const char *old_fqn = (c->v2_create_child_proposals_default_dh != NULL + ? c->v2_create_child_proposals_default_dh->common.fqn + : "no-PFS"); + const char *new_fqn = default_dh != NULL ? default_dh->common.fqn : "no-PFS"; + DBGF(DBG_CONTROL, "create child proposal's DH changed from %s to %s, flushing", + old_fqn, new_fqn); + free_ikev2_proposals(&c->v2_create_child_proposals); + c->v2_create_child_proposals_default_dh = default_dh; + } + return get_v2_child_proposals(&c->v2_create_child_proposals, c, why, + c->v2_create_child_proposals_default_dh); } struct ipsec_proto_info *ikev2_child_sa_proto_info(struct state *st, lset_t policy) @@ -2358,7 +2431,7 @@ { int propnum; const struct ikev2_proposal *proposal; - FOR_EACH_PROPOSAL(propnum, proposal, proposals) { + FOR_EACH_V2_PROPOSAL(propnum, proposal, proposals) { const struct ikev2_transforms *transforms = &proposal->transforms[IKEv2_TRANS_TYPE_DH]; int t; for (t = 0; t < transforms->transform[t].valid; t++) { @@ -2393,7 +2466,7 @@ { int propnum; const struct ikev2_proposal *proposal; - FOR_EACH_PROPOSAL(propnum, proposal, proposals) { + FOR_EACH_V2_PROPOSAL(propnum, proposal, proposals) { const struct ikev2_transforms *transforms = &proposal->transforms[IKEv2_TRANS_TYPE_DH]; const struct ikev2_transform *transform; FOR_EACH_TRANSFORM(transform, transforms) { diff -Naur libreswan-3.27-orig/programs/pluto/initiate.c libreswan-3.27/programs/pluto/initiate.c --- libreswan-3.27-orig/programs/pluto/initiate.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/initiate.c 2019-02-15 16:32:28.999835528 -0500 @@ -63,7 +63,7 @@ #include "log.h" #include "keys.h" #include "whack.h" -#include "alg_info.h" +#include "proposals.h" #include "spdb.h" #include "ike_alg.h" #include "kernel_alg.h" @@ -287,15 +287,12 @@ /* We will only request an IPsec SA if policy isn't empty * (ignoring Main Mode items). * This is a fudge, but not yet important. - * If we are to proceed asynchronously, whackfd will be NULL_FD. */ if (c->policy & (POLICY_ENCRYPT | POLICY_AUTHENTICATE)) { - struct alg_info_esp *alg = c->alg_info_esp; - struct db_sa *phase2_sa = kernel_alg_makedb( - c->policy, alg, TRUE); - - if (alg != NULL && phase2_sa == NULL) { + struct db_sa *phase2_sa = + kernel_alg_makedb(c->policy, c->child_proposals, TRUE); + if (c->child_proposals.p != NULL && phase2_sa == NULL) { whack_log(RC_LOG_SERIOUS, "cannot initiate: no acceptable kernel algorithms loaded"); reset_cur_connection(); diff -Naur libreswan-3.27-orig/programs/pluto/kernel_bsdkame.c libreswan-3.27/programs/pluto/kernel_bsdkame.c --- libreswan-3.27-orig/programs/pluto/kernel_bsdkame.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/kernel_bsdkame.c 2019-02-15 16:32:28.999835528 -0500 @@ -47,7 +47,6 @@ #include "whack.h" /* for RC_LOG_SERIOUS */ #include "packet.h" /* for pb_stream in nat_traversal.h */ #include "nat_traversal.h" -#include "alg_info.h" #include "kernel_alg.h" #include "kernel_sadb.h" diff -Naur libreswan-3.27-orig/programs/pluto/kernel.c libreswan-3.27/programs/pluto/kernel.c --- libreswan-3.27-orig/programs/pluto/kernel.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/kernel.c 2019-02-15 16:32:29.000835537 -0500 @@ -1176,7 +1176,6 @@ } } -#include "alg_info.h" #include "kernel_alg.h" void set_text_said(char *text_said, const ip_address *dst, diff -Naur libreswan-3.27-orig/programs/pluto/kernel_klips.c libreswan-3.27/programs/pluto/kernel_klips.c --- libreswan-3.27-orig/programs/pluto/kernel_klips.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/kernel_klips.c 2019-02-15 16:32:29.000835537 -0500 @@ -48,7 +48,6 @@ #include "nat_traversal.h" #include "server.h" -#include "alg_info.h" #include "kernel_alg.h" #include "ip_address.h" diff -Naur libreswan-3.27-orig/programs/pluto/kernel_mast.c libreswan-3.27/programs/pluto/kernel_mast.c --- libreswan-3.27-orig/programs/pluto/kernel_mast.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/kernel_mast.c 2019-02-15 16:32:29.001835546 -0500 @@ -48,7 +48,6 @@ #include "nat_traversal.h" #include "server.h" -#include "alg_info.h" #include "kernel_alg.h" static int next_free_mast_device = -1; diff -Naur libreswan-3.27-orig/programs/pluto/kernel_pfkey.c libreswan-3.27/programs/pluto/kernel_pfkey.c --- libreswan-3.27-orig/programs/pluto/kernel_pfkey.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/kernel_pfkey.c 2019-02-15 16:32:29.001835546 -0500 @@ -63,7 +63,6 @@ #include "nat_traversal.h" #include "lsw_select.h" -#include "alg_info.h" #include "kernel_alg.h" #include "ip_address.h" diff -Naur libreswan-3.27-orig/programs/pluto/plutoalg.c libreswan-3.27/programs/pluto/plutoalg.c --- libreswan-3.27-orig/programs/pluto/plutoalg.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/plutoalg.c 2019-02-15 16:32:29.002835556 -0500 @@ -34,7 +34,7 @@ #include "connections.h" #include "state.h" #include "kernel_alg.h" -#include "alg_info.h" +#include "proposals.h" #include "ike_alg.h" #include "ike_alg_integ.h" #include "ike_alg_encrypt.h" @@ -47,15 +47,16 @@ #include "ikev1.h" /* for ikev1_quick_dh() */ static bool kernel_alg_db_add(struct db_context *db_ctx, - const struct proposal_info *esp_info, + const struct proposal *proposal, lset_t policy, bool logit) { int ealg_i = SADB_EALG_NONE; + struct v1_proposal algs = v1_proposal(proposal); if (policy & POLICY_ENCRYPT) { - ealg_i = esp_info->encrypt->common.id[IKEv1_ESP_ID]; + ealg_i = algs.encrypt->common.id[IKEv1_ESP_ID]; /* already checked by the parser? */ - if (!kernel_alg_encrypt_ok(esp_info->encrypt)) { + if (!kernel_alg_encrypt_ok(algs.encrypt)) { if (logit) { loglog(RC_LOG_SERIOUS, "requested kernel enc ealg_id=%d not present", @@ -68,10 +69,10 @@ } } - int aalg_i = esp_info->integ->integ_ikev1_ah_transform; + int aalg_i = algs.integ->integ_ikev1_ah_transform; /* already checked by the parser? */ - if (!kernel_alg_integ_ok(esp_info->integ)) { + if (!kernel_alg_integ_ok(algs.integ)) { DBG_log("kernel_alg_db_add() kernel auth aalg_id=%d not present", aalg_i); return FALSE; @@ -82,32 +83,32 @@ db_trans_add(db_ctx, ealg_i); /* add ESP auth attr (if present) */ - if (esp_info->integ != &ike_alg_integ_none) { + if (algs.integ != &ike_alg_integ_none) { db_attr_add_values(db_ctx, AUTH_ALGORITHM, - esp_info->integ->common.id[IKEv1_ESP_ID]); + algs.integ->common.id[IKEv1_ESP_ID]); } /* add keylength if specified in esp= string */ - if (esp_info->enckeylen != 0) { - db_attr_add_values(db_ctx, - KEY_LENGTH, - esp_info->enckeylen); + if (algs.enckeylen != 0) { + db_attr_add_values(db_ctx, + KEY_LENGTH, + algs.enckeylen); } else { /* no key length - if required add default here and add another max entry */ - int def_ks = (esp_info->encrypt->keylen_omitted ? 0 - : esp_info->encrypt->keydeflen); + int def_ks = (algs.encrypt->keylen_omitted ? 0 + : algs.encrypt->keydeflen); if (def_ks != 0) { db_attr_add_values(db_ctx, KEY_LENGTH, def_ks); /* add this trans again with max key size */ - int max_ks = encrypt_max_key_bit_length(esp_info->encrypt); + int max_ks = encrypt_max_key_bit_length(algs.encrypt); if (def_ks != max_ks) { db_trans_add(db_ctx, ealg_i); - if (esp_info->integ != &ike_alg_integ_none) { + if (algs.integ != &ike_alg_integ_none) { db_attr_add_values(db_ctx, AUTH_ALGORITHM, - esp_info->integ->common.id[IKEv1_ESP_ID]); + algs.integ->common.id[IKEv1_ESP_ID]); } db_attr_add_values(db_ctx, KEY_LENGTH, @@ -120,8 +121,8 @@ db_trans_add(db_ctx, aalg_i); /* add ESP auth attr */ - db_attr_add_values(db_ctx, - AUTH_ALGORITHM, esp_info->integ->common.id[IKEv1_ESP_ID]); + db_attr_add_values(db_ctx, AUTH_ALGORITHM, + algs.integ->common.id[IKEv1_ESP_ID]); } return TRUE; @@ -135,7 +136,7 @@ * for now this function does free() previous returned * malloced pointer (this quirk allows easier spdb.c change) */ -static struct db_context *kernel_alg_db_new(struct alg_info_esp *alg_info, +static struct db_context *kernel_alg_db_new(struct child_proposals proposals, lset_t policy, bool logit) { unsigned int trans_cnt = 0; @@ -157,25 +158,24 @@ /* * Loop: for each element (struct esp_info) of - * alg_info, if kernel support is present then + * proposals, if kernel support is present then * build the transform (and attrs) * - * if NULL alg_info, propose everything ... + * if NULL proposals, propose everything ... */ bool success = TRUE; - if (alg_info != NULL) { - FOR_EACH_ESP_INFO(alg_info, proposal) { + if (proposals.p != NULL) { + FOR_EACH_PROPOSAL(proposals.p, proposal) { LSWDBGP(DBG_CONTROL | DBG_EMITTING, buf) { lswlogs(buf, "adding proposal: "); - lswlog_proposal_info(buf, proposal); + fmt_proposal(buf, proposal); } - if (!kernel_alg_db_add(ctx_new, proposal, - policy, logit)) + if (!kernel_alg_db_add(ctx_new, proposal, policy, logit)) success = FALSE; /* ??? should we break? */ } } else { - PEXPECT_LOG("%s", "alg_info should be non-NULL"); + PEXPECT_LOG("%s", "proposals should be non-NULL"); } if (!success) { @@ -268,7 +268,7 @@ * If this is NULL and PFS is required then callers fall back to using * the parent's DH algorithm. */ - const struct oakley_group_desc *dh = ikev1_quick_pfs(c->alg_info_esp); + const struct oakley_group_desc *dh = ikev1_quick_pfs(c->child_proposals); if (dh != NULL) { pfsbuf = dh->common.fqn; } else { @@ -278,7 +278,7 @@ pfsbuf = ""; } - if (c->alg_info_esp != NULL) { + if (c->child_proposals.p != NULL) { LSWLOG_WHACK(RC_COMMENT, buf) { /* * If DH (PFS) was specified in the esp= or @@ -299,7 +299,7 @@ */ lswlogf(buf, "\"%s\"%s: %s algorithms: ", c->name, instance, satype); - lswlog_alg_info(buf, &c->alg_info_esp->ai); + fmt_proposals(buf, c->child_proposals.p); } } @@ -326,10 +326,11 @@ } } -struct db_sa *kernel_alg_makedb(lset_t policy, struct alg_info_esp *ei, +struct db_sa *kernel_alg_makedb(lset_t policy, + struct child_proposals proposals, bool logit) { - if (ei == NULL) { + if (proposals.p == NULL) { struct db_sa *sadb; lset_t pm = POLICY_ENCRYPT | POLICY_AUTHENTICATE; @@ -344,7 +345,7 @@ return sadb; } - struct db_context *dbnew = kernel_alg_db_new(ei, policy, logit); + struct db_context *dbnew = kernel_alg_db_new(proposals, policy, logit); if (dbnew == NULL) { libreswan_log("failed to translate esp_info to proposal, returning empty"); diff -Naur libreswan-3.27-orig/programs/pluto/spdb.c libreswan-3.27/programs/pluto/spdb.c --- libreswan-3.27-orig/programs/pluto/spdb.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/spdb.c 2019-02-15 16:32:29.002835556 -0500 @@ -51,7 +51,6 @@ #include "crypto.h" -#include "alg_info.h" #include "kernel_alg.h" #include "ike_alg.h" #include "db_ops.h" diff -Naur libreswan-3.27-orig/programs/pluto/spdb.h libreswan-3.27/programs/pluto/spdb.h --- libreswan-3.27-orig/programs/pluto/spdb.h 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/spdb.h 2019-02-15 16:32:29.002835556 -0500 @@ -171,12 +171,12 @@ struct alg_info_ike; struct alg_info_esp; -extern struct db_sa *oakley_alg_makedb(struct alg_info_ike *ai, +extern struct db_sa *oakley_alg_makedb(const struct ike_proposals proposals, enum ikev1_auth_method auth_method, bool single_dh); extern struct db_sa *kernel_alg_makedb(lset_t policy, - struct alg_info_esp *ei, + const struct child_proposals proposals, bool logit); #endif /* _SPDB_H_ */ diff -Naur libreswan-3.27-orig/programs/pluto/spdb_struct.c libreswan-3.27/programs/pluto/spdb_struct.c --- libreswan-3.27-orig/programs/pluto/spdb_struct.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/spdb_struct.c 2019-02-15 16:32:29.003835565 -0500 @@ -45,7 +45,6 @@ #include "crypto.h" -#include "alg_info.h" #include "kernel_alg.h" #include "ike_alg.h" #include "db_ops.h" @@ -82,30 +81,31 @@ * one DH group. */ -static struct db_sa *oakley_alg_mergedb(struct alg_info_ike *ai, +static struct db_sa *oakley_alg_mergedb(struct ike_proposals ike_proposals, enum ikev1_auth_method auth_method, bool single_dh); -static struct alg_info_ike *ikev1_default_ike_info(void) +static struct ike_proposals ikev1_default_ike_info(void) { static const struct proposal_policy policy = { - .ikev1 = TRUE, + .version = IKEv1, + .check_pfs_vs_dh = false, .alg_is_ok = ike_alg_is_ike, .warning = libreswan_log, }; - char err[100]; - struct alg_info_ike *defaults = - alg_info_ike_create_from_str(&policy, NULL, - err, sizeof(err)); - if (defaults == NULL) { - PEXPECT_LOG("Invalid IKEv1 default algorithms: %s", err); + struct proposal_parser *parser = ike_proposal_parser(&policy); + struct ike_proposals defaults = { .p = proposals_from_str(parser, NULL), }; + if (defaults.p == NULL) { + PEXPECT_LOG("Invalid IKEv1 default algorithms: %s", + parser->error); } + free_proposal_parser(&parser); return defaults; } -struct db_sa *oakley_alg_makedb(struct alg_info_ike *ai, +struct db_sa *oakley_alg_makedb(const struct ike_proposals ike_proposals, enum ikev1_auth_method auth_method, bool single_dh) { @@ -114,26 +114,25 @@ * standard defaults. */ - if (ai == NULL) { + if (ike_proposals.p == NULL) { DBG(DBG_CONTROL, DBG_log( "no specific IKE algorithms specified - using defaults")); - struct alg_info_ike *default_info - = ikev1_default_ike_info(); + struct ike_proposals default_info = ikev1_default_ike_info(); struct db_sa *new_db = oakley_alg_mergedb(default_info, auth_method, single_dh); - pfree(default_info); + proposals_delref(&default_info.p); return new_db; } else { - return oakley_alg_mergedb(ai, auth_method, single_dh); + return oakley_alg_mergedb(ike_proposals, auth_method, single_dh); } } -struct db_sa *oakley_alg_mergedb(struct alg_info_ike *ai, +struct db_sa *oakley_alg_mergedb(struct ike_proposals ike_proposals, enum ikev1_auth_method auth_method, bool single_dh) { - passert(ai != NULL); + passert(ike_proposals.p != NULL); struct db_sa *gsp = NULL; @@ -150,26 +149,28 @@ * when creating each item, we will use the first transform * from the base item as the template. */ - FOR_EACH_IKE_INFO(ai, ike_info) { + FOR_EACH_PROPOSAL(ike_proposals.p, proposal) { struct db_sa *emp_sp; - passert(ike_info->encrypt); - passert(ike_info->prf); - passert(ike_info->dh); - - unsigned ealg = ike_info->encrypt->common.ikev1_oakley_id; - unsigned halg = ike_info->prf->common.ikev1_oakley_id; - unsigned modp = ike_info->dh->group; - unsigned eklen = ike_info->enckeylen; + struct v1_proposal algs = v1_proposal(proposal); + + passert(algs.encrypt != NULL); + passert(algs.prf != NULL); + passert(algs.dh != NULL); + + unsigned ealg = algs.encrypt->common.ikev1_oakley_id; + unsigned halg = algs.prf->common.ikev1_oakley_id; + unsigned modp = algs.dh->group; + unsigned eklen = algs.enckeylen; DBG(DBG_CONTROL, DBG_log("oakley_alg_makedb() processing ealg=%s=%u halg=%s=%u modp=%s=%u eklen=%u", - ike_info->encrypt->common.name, ealg, - ike_info->prf->common.name, halg, - ike_info->dh->common.name, modp, + algs.encrypt->common.name, ealg, + algs.prf->common.name, halg, + algs.dh->common.name, modp, eklen)); - const struct encrypt_desc *enc_desc = ike_info->encrypt; + const struct encrypt_desc *enc_desc = algs.encrypt; if (eklen != 0 && !encrypt_has_key_bit_length(enc_desc, eklen)) { PEXPECT_LOG("IKEv1 proposal with ENCRYPT%s (specified) keylen:%d, not valid, should have been dropped", enc_desc->common.name, @@ -251,7 +252,7 @@ * a different DH group, we try to deal with this. */ if (single_dh && transcnt > 0 && - ike_info->dh->group != last_modp) { + algs.dh->group != last_modp) { if ( #ifdef USE_DH2 last_modp == OAKLEY_GROUP_MODP1024 || @@ -269,13 +270,13 @@ } loglog(RC_LOG_SERIOUS, - "transform (%s,%s,%s keylen %zd) ignored.", + "transform (%s,%s,%s keylen %d) ignored.", enum_name(&oakley_enc_names, - ike_info->encrypt->common.ikev1_oakley_id), + algs.encrypt->common.ikev1_oakley_id), enum_name(&oakley_hash_names, - ike_info->prf->common.ikev1_oakley_id), - ike_info->dh->common.name, - ike_info->enckeylen); + algs.prf->common.ikev1_oakley_id), + algs.dh->common.name, + algs.enckeylen); free_sa(&emp_sp); } else { /* @@ -303,9 +304,9 @@ * Exclude 3des et.al. which do not include * default key lengths in the proposal. */ - if (ike_info->enckeylen == 0 && - !ike_info->encrypt->keylen_omitted) { - const struct encrypt_desc *enc_desc = ike_info->encrypt; + if (algs.enckeylen == 0 && + !algs.encrypt->keylen_omitted) { + const struct encrypt_desc *enc_desc = algs.encrypt; int def_ks = enc_desc->keydeflen; passert(def_ks); /* ike=null not supported */ int max_ks = encrypt_max_key_bit_length(enc_desc); @@ -375,7 +376,7 @@ emp_sp = NULL; } } - last_modp = ike_info->dh->group; + last_modp = algs.dh->group; } transcnt++; diff -Naur libreswan-3.27-orig/programs/pluto/terminate.c libreswan-3.27/programs/pluto/terminate.c --- libreswan-3.27-orig/programs/pluto/terminate.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/pluto/terminate.c 2019-02-15 16:32:29.003835565 -0500 @@ -53,7 +53,6 @@ #include "log.h" #include "keys.h" #include "whack.h" -#include "alg_info.h" #include "spdb.h" #include "ike_alg.h" #include "kernel_alg.h" diff -Naur libreswan-3.27-orig/programs/spi/spi.c libreswan-3.27/programs/spi/spi.c --- libreswan-3.27-orig/programs/spi/spi.c 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/programs/spi/spi.c 2019-02-15 16:32:29.003835565 -0500 @@ -61,7 +61,6 @@ #include "lswlog.h" #include "lswtool.h" -#include "alg_info.h" #include "kernel_alg.h" #include "kernel_sadb.h" #include "pfkey_help.h" diff -Naur libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v1.pfs.txt libreswan-3.27/testing/pluto/algparse-01/algparse.v1.pfs.txt --- libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v1.pfs.txt 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/testing/pluto/algparse-01/algparse.v1.pfs.txt 2019-02-15 16:46:01.379390213 -0500 @@ -386,3 +386,9 @@ ERROR: IKE PRF algorithm 'id2' is not recognized algparse -v1 -pfs 'ike=aes_ccm' ERROR: IKE encryption algorithm 'aes_ccm' is not supported by IKEv1 +algparse -v1 -pfs 'ike=aes_gcm-sha1-none-modp2048' + ERROR: IKE encryption algorithm 'aes_gcm' is not supported by IKEv1 +algparse -v1 -pfs 'ike=aes_gcm+aes_gcm-sha1-none-modp2048' + ERROR: IKE encryption algorithm 'aes_gcm+aes_gcm' is not recognized +algparse -v1 -pfs 'ike=aes+aes_gcm' + ERROR: IKE encryption algorithm 'aes+aes_gcm' is not recognized diff -Naur libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v1.txt libreswan-3.27/testing/pluto/algparse-01/algparse.v1.txt --- libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v1.txt 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/testing/pluto/algparse-01/algparse.v1.txt 2019-02-15 16:46:01.379390213 -0500 @@ -418,3 +418,9 @@ ERROR: IKE PRF algorithm 'id2' is not recognized algparse -v1 'ike=aes_ccm' ERROR: IKE encryption algorithm 'aes_ccm' is not supported by IKEv1 +algparse -v1 'ike=aes_gcm-sha1-none-modp2048' + ERROR: IKE encryption algorithm 'aes_gcm' is not supported by IKEv1 +algparse -v1 'ike=aes_gcm+aes_gcm-sha1-none-modp2048' + ERROR: IKE encryption algorithm 'aes_gcm+aes_gcm' is not recognized +algparse -v1 'ike=aes+aes_gcm' + ERROR: IKE encryption algorithm 'aes+aes_gcm' is not recognized diff -Naur libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v2.pfs.txt libreswan-3.27/testing/pluto/algparse-01/algparse.v2.pfs.txt --- libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v2.pfs.txt 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/testing/pluto/algparse-01/algparse.v2.pfs.txt 2019-02-15 16:50:12.777728085 -0500 @@ -1,11 +1,11 @@ algparse -v2 -pfs 'esp' - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'esp=' ERROR: String ended with invalid char, just after "" algparse -v2 -pfs 'esp=aes' - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'esp=aes;modp2048' - AES_CBC-HMAC_SHA1_96-MODP2048 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-MODP2048 algparse -v2 -pfs 'esp=aes-sha1' AES_CBC-HMAC_SHA1_96 algparse -v2 -pfs 'esp=aes-sha1' @@ -13,7 +13,7 @@ algparse -v2 -pfs 'esp=aes-sha1-modp2048' AES_CBC-HMAC_SHA1_96-MODP2048 algparse -v2 -pfs 'esp=aes-128' - AES_CBC_128-HMAC_SHA1_96 + AES_CBC_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'esp=aes-128-sha1' AES_CBC_128-HMAC_SHA1_96 algparse -v2 -pfs 'esp=aes-128-sha1' @@ -41,7 +41,7 @@ algparse -v2 -pfs 'esp=null-sha1' NULL-HMAC_SHA1_96 algparse -v2 -pfs 'esp=aes_cbc' - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'esp=aes-sha' AES_CBC-HMAC_SHA1_96 algparse -v2 -pfs 'esp=aes-sha1' @@ -73,13 +73,13 @@ algparse -v2 -pfs 'esp=aes256-sha2_512' AES_CBC_256-HMAC_SHA2_512_256 algparse -v2 -pfs 'esp=camellia' - CAMELLIA_CBC-HMAC_SHA1_96 + CAMELLIA_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'esp=camellia128' - CAMELLIA_CBC_128-HMAC_SHA1_96 + CAMELLIA_CBC_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'esp=camellia192' - CAMELLIA_CBC_192-HMAC_SHA1_96 + CAMELLIA_CBC_192-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'esp=camellia256' - CAMELLIA_CBC_256-HMAC_SHA1_96 + CAMELLIA_CBC_256-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'esp=aes_ccm' AES_CCM_16-NONE algparse -v2 -pfs 'esp=aes_ccm_a-128-null' @@ -181,19 +181,19 @@ algparse -v2 -pfs 'esp=aes_gcm_16_256-null' AES_GCM_16_256-NONE algparse -v2 -pfs 'esp=aes_ctr' - AES_CTR-HMAC_SHA1_96 + AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'esp=aesctr' - AES_CTR-HMAC_SHA1_96 + AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'esp=aes_ctr128' - AES_CTR_128-HMAC_SHA1_96 + AES_CTR_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'esp=aes_ctr192' - AES_CTR_192-HMAC_SHA1_96 + AES_CTR_192-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'esp=aes_ctr256' - AES_CTR_256-HMAC_SHA1_96 + AES_CTR_256-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'esp=serpent' - SERPENT_CBC-HMAC_SHA1_96 + SERPENT_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'esp=twofish' - TWOFISH_CBC-HMAC_SHA1_96 + TWOFISH_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'esp=camellia_cbc_256-hmac_sha2_512_256;modp8192' CAMELLIA_CBC_256-HMAC_SHA2_512_256-MODP8192 algparse -v2 -pfs 'esp=null_auth_aes_gmac_256-null;modp8192' @@ -210,12 +210,12 @@ algparse -v2 -pfs 'esp=aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192' AES_CBC-HMAC_SHA1_96-MODP8192 algparse -v2 -pfs 'esp=aes;none' - AES_CBC-HMAC_SHA1_96-NONE + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-NONE algparse -v2 -pfs 'esp=aes;none,aes' ERROR: either all or no ESP proposals should specify DH algparse -v2 -pfs 'esp=aes;none,aes;modp2048' - AES_CBC-HMAC_SHA1_96-NONE - AES_CBC-HMAC_SHA1_96-MODP2048 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-NONE + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-MODP2048 algparse -v2 -pfs 'esp=aes-sha1-none' AES_CBC-HMAC_SHA1_96-NONE algparse -v2 -pfs 'esp=aes-sha1;none' @@ -293,7 +293,7 @@ algparse -v2 -pfs 'esp=3des-sha1-modp8192,3des-sha2-modp2048' ERROR: more than one IKEv2 ESP DH algorithm (MODP8192, MODP2048) requires unimplemented CHILD_SA INVALID_KE algparse -v2 -pfs 'ah' - HMAC_SHA1_96 + HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 -pfs 'ah=' ERROR: String ended with invalid char, just after "" algparse -v2 -pfs 'ah=md5' @@ -345,32 +345,23 @@ algparse -v2 -pfs 'ah=ripemd' ERROR: AH integrity algorithm 'ripemd' is not recognized algparse -v2 -pfs 'ike' - AES_CBC-HMAC_SHA2_256-MODP2048 - AES_CBC-HMAC_SHA2_512-MODP2048 - AES_CBC-HMAC_SHA1-MODP2048 - 3DES_CBC-HMAC_SHA2_256-MODP2048 - 3DES_CBC-HMAC_SHA2_512-MODP2048 - 3DES_CBC-HMAC_SHA1-MODP2048 + AES_CBC+3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -v2 -pfs 'ike=' ERROR: String ended with invalid char, just after "" algparse -v2 -pfs 'ike=3des-sha1' - 3DES_CBC-HMAC_SHA1-MODP2048 + 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -v2 -pfs 'ike=3des-sha1' - 3DES_CBC-HMAC_SHA1-MODP2048 + 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -v2 -pfs 'ike=3des-sha1;modp1536' 3DES_CBC-HMAC_SHA1-MODP1536 algparse -v2 -pfs 'ike=3des;dh21' - 3DES_CBC-HMAC_SHA2_256-DH21 - 3DES_CBC-HMAC_SHA2_512-DH21 - 3DES_CBC-HMAC_SHA1-DH21 + 3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-DH21 algparse -v2 -pfs 'ike=3des-sha1;dh21' 3DES_CBC-HMAC_SHA1-DH21 algparse -v2 -pfs 'ike=3des-sha1-ecp_521' 3DES_CBC-HMAC_SHA1-DH21 algparse -v2 -pfs 'ike=aes_gcm' - AES_GCM_16-HMAC_SHA2_256-MODP2048 - AES_GCM_16-HMAC_SHA2_512-MODP2048 - AES_GCM_16-HMAC_SHA1-MODP2048 + AES_GCM_16-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -v2 -pfs 'ike=aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192' AES_CBC-HMAC_SHA1-MODP8192 algparse -v2 -pfs 'ike=aes;none' @@ -381,3 +372,10 @@ ERROR: IKE PRF algorithm 'id2' is not recognized algparse -v2 -pfs 'ike=aes_ccm' ERROR: IKE encryption algorithm 'aes_ccm' is not supported +algparse -v2 -pfs 'ike=aes_gcm-sha1-none-modp2048' + ERROR: 'modp2048' unexpected +algparse -v2 -pfs 'ike=aes_gcm+aes_gcm-sha1-none-modp2048' + WARNING: discarding duplicate algorithm 'aes_gcm_16' + ERROR: 'modp2048' unexpected +algparse -v2 -pfs 'ike=aes+aes_gcm' + ERROR: AEAD and non-AEAD IKE encryption algorithm can not be combined diff -Naur libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v2.txt libreswan-3.27/testing/pluto/algparse-01/algparse.v2.txt --- libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v2.txt 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/testing/pluto/algparse-01/algparse.v2.txt 2019-02-15 16:50:12.778728094 -0500 @@ -1,12 +1,12 @@ algparse -v2 'esp' - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=' ERROR: String ended with invalid char, just after "" algparse -v2 'esp=aes' - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=aes;modp2048' WARNING: ignoring ESP DH algorithm MODP2048 as PFS policy is disabled - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=aes-sha1' AES_CBC-HMAC_SHA1_96 algparse -v2 'esp=aes-sha1' @@ -15,7 +15,7 @@ WARNING: ignoring ESP DH algorithm MODP2048 as PFS policy is disabled AES_CBC-HMAC_SHA1_96 algparse -v2 'esp=aes-128' - AES_CBC_128-HMAC_SHA1_96 + AES_CBC_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=aes-128-sha1' AES_CBC_128-HMAC_SHA1_96 algparse -v2 'esp=aes-128-sha1' @@ -49,7 +49,7 @@ algparse -v2 'esp=null-sha1' NULL-HMAC_SHA1_96 algparse -v2 'esp=aes_cbc' - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=aes-sha' AES_CBC-HMAC_SHA1_96 algparse -v2 'esp=aes-sha1' @@ -81,13 +81,13 @@ algparse -v2 'esp=aes256-sha2_512' AES_CBC_256-HMAC_SHA2_512_256 algparse -v2 'esp=camellia' - CAMELLIA_CBC-HMAC_SHA1_96 + CAMELLIA_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=camellia128' - CAMELLIA_CBC_128-HMAC_SHA1_96 + CAMELLIA_CBC_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=camellia192' - CAMELLIA_CBC_192-HMAC_SHA1_96 + CAMELLIA_CBC_192-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=camellia256' - CAMELLIA_CBC_256-HMAC_SHA1_96 + CAMELLIA_CBC_256-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=aes_ccm' AES_CCM_16-NONE algparse -v2 'esp=aes_ccm_a-128-null' @@ -189,19 +189,19 @@ algparse -v2 'esp=aes_gcm_16_256-null' AES_GCM_16_256-NONE algparse -v2 'esp=aes_ctr' - AES_CTR-HMAC_SHA1_96 + AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=aesctr' - AES_CTR-HMAC_SHA1_96 + AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=aes_ctr128' - AES_CTR_128-HMAC_SHA1_96 + AES_CTR_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=aes_ctr192' - AES_CTR_192-HMAC_SHA1_96 + AES_CTR_192-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=aes_ctr256' - AES_CTR_256-HMAC_SHA1_96 + AES_CTR_256-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=serpent' - SERPENT_CBC-HMAC_SHA1_96 + SERPENT_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=twofish' - TWOFISH_CBC-HMAC_SHA1_96 + TWOFISH_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=camellia_cbc_256-hmac_sha2_512_256;modp8192' WARNING: ignoring ESP DH algorithm MODP8192 as PFS policy is disabled CAMELLIA_CBC_256-HMAC_SHA2_512_256 @@ -228,16 +228,16 @@ AES_CBC-HMAC_SHA1_96 algparse -v2 'esp=aes;none' WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=aes;none,aes' WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled - AES_CBC-HMAC_SHA1_96 - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=aes;none,aes;modp2048' WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled WARNING: ignoring ESP DH algorithm MODP2048 as PFS policy is disabled - AES_CBC-HMAC_SHA1_96 - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'esp=aes-sha1-none' WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled AES_CBC-HMAC_SHA1_96 @@ -332,7 +332,7 @@ 3DES_CBC-HMAC_SHA1_96 3DES_CBC-HMAC_SHA2_256_128 algparse -v2 'ah' - HMAC_SHA1_96 + HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -v2 'ah=' ERROR: String ended with invalid char, just after "" algparse -v2 'ah=md5' @@ -388,32 +388,23 @@ algparse -v2 'ah=ripemd' ERROR: AH integrity algorithm 'ripemd' is not recognized algparse -v2 'ike' - AES_CBC-HMAC_SHA2_256-MODP2048 - AES_CBC-HMAC_SHA2_512-MODP2048 - AES_CBC-HMAC_SHA1-MODP2048 - 3DES_CBC-HMAC_SHA2_256-MODP2048 - 3DES_CBC-HMAC_SHA2_512-MODP2048 - 3DES_CBC-HMAC_SHA1-MODP2048 + AES_CBC+3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -v2 'ike=' ERROR: String ended with invalid char, just after "" algparse -v2 'ike=3des-sha1' - 3DES_CBC-HMAC_SHA1-MODP2048 + 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -v2 'ike=3des-sha1' - 3DES_CBC-HMAC_SHA1-MODP2048 + 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -v2 'ike=3des-sha1;modp1536' 3DES_CBC-HMAC_SHA1-MODP1536 algparse -v2 'ike=3des;dh21' - 3DES_CBC-HMAC_SHA2_256-DH21 - 3DES_CBC-HMAC_SHA2_512-DH21 - 3DES_CBC-HMAC_SHA1-DH21 + 3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-DH21 algparse -v2 'ike=3des-sha1;dh21' 3DES_CBC-HMAC_SHA1-DH21 algparse -v2 'ike=3des-sha1-ecp_521' 3DES_CBC-HMAC_SHA1-DH21 algparse -v2 'ike=aes_gcm' - AES_GCM_16-HMAC_SHA2_256-MODP2048 - AES_GCM_16-HMAC_SHA2_512-MODP2048 - AES_GCM_16-HMAC_SHA1-MODP2048 + AES_GCM_16-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -v2 'ike=aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192' AES_CBC-HMAC_SHA1-MODP8192 algparse -v2 'ike=aes;none' @@ -424,3 +415,10 @@ ERROR: IKE PRF algorithm 'id2' is not recognized algparse -v2 'ike=aes_ccm' ERROR: IKE encryption algorithm 'aes_ccm' is not supported +algparse -v2 'ike=aes_gcm-sha1-none-modp2048' + ERROR: 'modp2048' unexpected +algparse -v2 'ike=aes_gcm+aes_gcm-sha1-none-modp2048' + WARNING: discarding duplicate algorithm 'aes_gcm_16' + ERROR: 'modp2048' unexpected +algparse -v2 'ike=aes+aes_gcm' + ERROR: AEAD and non-AEAD IKE encryption algorithm can not be combined diff -Naur libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v.txt libreswan-3.27/testing/pluto/algparse-01/algparse.v.txt --- libreswan-3.27-orig/testing/pluto/algparse-01/algparse.v.txt 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/testing/pluto/algparse-01/algparse.v.txt 2019-02-15 16:32:29.004835574 -0500 @@ -13,7 +13,7 @@ algparse: SERPENT_CBC IKEv1: IKE ESP IKEv2: IKE ESP {256,192,*128} serpent algparse: TWOFISH_CBC IKEv1: IKE ESP IKEv2: IKE ESP {256,192,*128} twofish algparse: TWOFISH_SSH IKEv1: IKE IKEv2: IKE ESP {256,192,*128} twofish_cbc_ssh -algparse: NULL_AUTH_AES_GMAC IKEv1: ESP IKEv2: ESP {256,192,*128} aes_gmac +algparse: NULL_AUTH_AES_GMAC IKEv1: ESP IKEv2: ESP FIPS {256,192,*128} aes_gmac algparse: NULL IKEv1: ESP IKEv2: ESP [] algparse: CHACHA20_POLY1305 IKEv1: IKEv2: IKE ESP [*256] chacha20poly1305 algparse: Hash algorithms: @@ -28,17 +28,17 @@ algparse: HMAC_SHA2_256 IKEv1: IKE IKEv2: IKE FIPS sha2, sha256, sha2_256 algparse: HMAC_SHA2_384 IKEv1: IKE IKEv2: IKE FIPS sha384, sha2_384 algparse: HMAC_SHA2_512 IKEv1: IKE IKEv2: IKE FIPS sha512, sha2_512 -algparse: AES_XCBC IKEv1: IKEv2: IKE FIPS aes128_xcbc +algparse: AES_XCBC IKEv1: IKEv2: IKE aes128_xcbc algparse: Integrity algorithms: algparse: HMAC_MD5_96 IKEv1: IKE ESP AH IKEv2: IKE ESP AH md5, hmac_md5 algparse: HMAC_SHA1_96 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha, sha1, sha1_96, hmac_sha1 -algparse: HMAC_SHA2_512_256 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha512, sha2_512, hmac_sha2_512 -algparse: HMAC_SHA2_384_192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha384, sha2_384, hmac_sha2_384 -algparse: HMAC_SHA2_256_128 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha2, sha256, sha2_256, hmac_sha2_256 +algparse: HMAC_SHA2_512_256 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha512, sha2_512, sha2_512_256, hmac_sha2_512 +algparse: HMAC_SHA2_384_192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha384, sha2_384, sha2_384_192, hmac_sha2_384 +algparse: HMAC_SHA2_256_128 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha2, sha256, sha2_256, sha2_256_128, hmac_sha2_256 algparse: HMAC_SHA2_256_TRUNCBUG IKEv1: ESP AH IKEv2: AH -algparse: AES_XCBC_96 IKEv1: ESP AH IKEv2: IKE ESP AH FIPS aes_xcbc, aes128_xcbc, aes128_xcbc_96 +algparse: AES_XCBC_96 IKEv1: ESP AH IKEv2: IKE ESP AH aes_xcbc, aes128_xcbc, aes128_xcbc_96 algparse: AES_CMAC_96 IKEv1: ESP AH IKEv2: ESP AH FIPS aes_cmac -algparse: NONE IKEv1: ESP IKEv2: ESP FIPS null +algparse: NONE IKEv1: ESP IKEv2: IKE ESP FIPS null algparse: DH algorithms: algparse: NONE IKEv1: IKEv2: IKE ESP AH FIPS null, dh0 algparse: MODP1024 IKEv1: IKE ESP AH IKEv2: IKE ESP AH dh2 @@ -48,8 +48,8 @@ algparse: MODP4096 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh16 algparse: MODP6144 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh17 algparse: MODP8192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh18 -algparse: DH19 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_256 -algparse: DH20 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_384 -algparse: DH21 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_521 +algparse: DH19 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_256, ecp256 +algparse: DH20 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_384, ecp384 +algparse: DH21 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_521, ecp521 algparse: DH31 IKEv1: IKE IKEv2: IKE ESP AH curve25519 algparse: leak detective found no leaks diff -Naur libreswan-3.27-orig/testing/pluto/algparse-01/west.conf libreswan-3.27/testing/pluto/algparse-01/west.conf --- libreswan-3.27-orig/testing/pluto/algparse-01/west.conf 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/testing/pluto/algparse-01/west.conf 2019-02-15 16:32:29.004835574 -0500 @@ -10,4 +10,7 @@ protostack=netkey plutodebug=all +conn %default + ikev2=no + include /testing/baseconfigs/all/etc/ipsec.d/ipsec.conf.common diff -Naur libreswan-3.27-orig/testing/pluto/algparse-01/west.console.txt libreswan-3.27/testing/pluto/algparse-01/west.console.txt --- libreswan-3.27-orig/testing/pluto/algparse-01/west.console.txt 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/testing/pluto/algparse-01/west.console.txt 2019-02-15 16:32:29.005835584 -0500 @@ -5,8 +5,6 @@ ../bin/algparse.sh PATH/libexec/ipsec/algparse algparse*.txt PATH/libexec/ipsec/algparse -v1 -pfs -t # algparse.v1.pfs.txt PATH/libexec/ipsec/algparse -v1 -t # algparse.v1.txt -PATH/libexec/ipsec/algparse -v1 -v2 -pfs -t # algparse.v1.v2.pfs.txt -PATH/libexec/ipsec/algparse -v1 -v2 -t # algparse.v1.v2.txt PATH/libexec/ipsec/algparse -v2 -pfs -t # algparse.v2.pfs.txt PATH/libexec/ipsec/algparse -v2 -t # algparse.v2.txt PATH/libexec/ipsec/algparse -v # algparse.v.txt @@ -48,7 +46,7 @@ SERPENT_CBC IKEv1: IKE ESP IKEv2: IKE ESP {256,192,*128} serpent TWOFISH_CBC IKEv1: IKE ESP IKEv2: IKE ESP {256,192,*128} twofish TWOFISH_SSH IKEv1: IKE IKEv2: IKE ESP {256,192,*128} twofish_cbc_ssh - NULL_AUTH_AES_GMAC IKEv1: ESP IKEv2: ESP {256,192,*128} aes_gmac + NULL_AUTH_AES_GMAC IKEv1: ESP IKEv2: ESP FIPS {256,192,*128} aes_gmac NULL IKEv1: ESP IKEv2: ESP [] CHACHA20_POLY1305 IKEv1: IKEv2: IKE ESP [*256] chacha20poly1305 Hash algorithms: @@ -63,7 +61,7 @@ HMAC_SHA2_256 IKEv1: IKE IKEv2: IKE FIPS sha2, sha256, sha2_256 HMAC_SHA2_384 IKEv1: IKE IKEv2: IKE FIPS sha384, sha2_384 HMAC_SHA2_512 IKEv1: IKE IKEv2: IKE FIPS sha512, sha2_512 - AES_XCBC IKEv1: IKEv2: IKE FIPS aes128_xcbc + AES_XCBC IKEv1: IKEv2: IKE aes128_xcbc Integrity algorithms: HMAC_MD5_96 IKEv1: IKE ESP AH IKEv2: IKE ESP AH md5, hmac_md5 HMAC_SHA1_96 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha, sha1, sha1_96, hmac_sha1 @@ -71,7 +69,7 @@ HMAC_SHA2_384_192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha384, sha2_384, hmac_sha2_384 HMAC_SHA2_256_128 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha2, sha256, sha2_256, hmac_sha2_256 HMAC_SHA2_256_TRUNCBUG IKEv1: ESP AH IKEv2: AH - AES_XCBC_96 IKEv1: ESP AH IKEv2: IKE ESP AH FIPS aes_xcbc, aes128_xcbc, aes128_xcbc_96 + AES_XCBC_96 IKEv1: ESP AH IKEv2: IKE ESP AH aes_xcbc, aes128_xcbc, aes128_xcbc_96 AES_CMAC_96 IKEv1: ESP AH IKEv2: ESP AH FIPS aes_cmac NONE IKEv1: ESP IKEv2: ESP FIPS null DH algorithms: diff -Naur libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v1.pfs.txt libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v1.pfs.txt --- libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v1.pfs.txt 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v1.pfs.txt 2019-02-15 16:46:01.380390223 -0500 @@ -57,7 +57,7 @@ algparse -fips -v1 -pfs 'esp=aes128-sha1' AES_CBC_128-HMAC_SHA1_96 algparse -fips -v1 -pfs 'esp=aes128-aes_xcbc' - AES_CBC_128-AES_XCBC_96 + ERROR: ESP integrity algorithm 'aes_xcbc' is not supported algparse -fips -v1 -pfs 'esp=aes192-sha1' AES_CBC_192-HMAC_SHA1_96 algparse -fips -v1 -pfs 'esp=aes256-sha1' @@ -197,7 +197,7 @@ algparse -fips -v1 -pfs 'esp=camellia_cbc_256-hmac_sha2_512_256;modp8192' ERROR: ESP encryption algorithm 'camellia_cbc_256' is not supported algparse -fips -v1 -pfs 'esp=null_auth_aes_gmac_256-null;modp8192' - ERROR: ESP encryption algorithm 'null_auth_aes_gmac_256' is not supported + NULL_AUTH_AES_GMAC_256-NONE-MODP8192 algparse -fips -v1 -pfs 'esp=3des-sha1;modp8192' 3DES_CBC-HMAC_SHA1_96-MODP8192 algparse -fips -v1 -pfs 'esp=3des-sha1-modp8192' @@ -318,7 +318,7 @@ algparse -fips -v1 -pfs 'ah=sha2_512' HMAC_SHA2_512_256 algparse -fips -v1 -pfs 'ah=aes_xcbc' - AES_XCBC_96 + ERROR: AH integrity algorithm 'aes_xcbc' is not supported algparse -fips -v1 -pfs 'ah=sha2-none' ERROR: AH DH algorithm 'none' is not supported by IKEv1 algparse -fips -v1 -pfs 'ah=sha2;none' @@ -378,3 +378,9 @@ ERROR: IKE PRF algorithm 'id2' is not recognized algparse -fips -v1 -pfs 'ike=aes_ccm' ERROR: IKE encryption algorithm 'aes_ccm' is not supported by IKEv1 +algparse -fips -v1 -pfs 'ike=aes_gcm-sha1-none-modp2048' + ERROR: IKE encryption algorithm 'aes_gcm' is not supported by IKEv1 +algparse -fips -v1 -pfs 'ike=aes_gcm+aes_gcm-sha1-none-modp2048' + ERROR: IKE encryption algorithm 'aes_gcm+aes_gcm' is not recognized +algparse -fips -v1 -pfs 'ike=aes+aes_gcm' + ERROR: IKE encryption algorithm 'aes+aes_gcm' is not recognized diff -Naur libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v1.txt libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v1.txt --- libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v1.txt 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v1.txt 2019-02-15 16:46:01.380390223 -0500 @@ -61,7 +61,7 @@ algparse -fips -v1 'esp=aes128-sha1' AES_CBC_128-HMAC_SHA1_96 algparse -fips -v1 'esp=aes128-aes_xcbc' - AES_CBC_128-AES_XCBC_96 + ERROR: ESP integrity algorithm 'aes_xcbc' is not supported algparse -fips -v1 'esp=aes192-sha1' AES_CBC_192-HMAC_SHA1_96 algparse -fips -v1 'esp=aes256-sha1' @@ -201,7 +201,8 @@ algparse -fips -v1 'esp=camellia_cbc_256-hmac_sha2_512_256;modp8192' ERROR: ESP encryption algorithm 'camellia_cbc_256' is not supported algparse -fips -v1 'esp=null_auth_aes_gmac_256-null;modp8192' - ERROR: ESP encryption algorithm 'null_auth_aes_gmac_256' is not supported + WARNING: ignoring ESP DH algorithm MODP8192 as PFS policy is disabled + NULL_AUTH_AES_GMAC_256-NONE algparse -fips -v1 'esp=3des-sha1;modp8192' WARNING: ignoring ESP DH algorithm MODP8192 as PFS policy is disabled 3DES_CBC-HMAC_SHA1_96 @@ -345,7 +346,7 @@ algparse -fips -v1 'ah=sha2_512' HMAC_SHA2_512_256 algparse -fips -v1 'ah=aes_xcbc' - AES_XCBC_96 + ERROR: AH integrity algorithm 'aes_xcbc' is not supported algparse -fips -v1 'ah=sha2-none' ERROR: AH DH algorithm 'none' is not supported by IKEv1 algparse -fips -v1 'ah=sha2;none' @@ -406,3 +407,9 @@ ERROR: IKE PRF algorithm 'id2' is not recognized algparse -fips -v1 'ike=aes_ccm' ERROR: IKE encryption algorithm 'aes_ccm' is not supported by IKEv1 +algparse -fips -v1 'ike=aes_gcm-sha1-none-modp2048' + ERROR: IKE encryption algorithm 'aes_gcm' is not supported by IKEv1 +algparse -fips -v1 'ike=aes_gcm+aes_gcm-sha1-none-modp2048' + ERROR: IKE encryption algorithm 'aes_gcm+aes_gcm' is not recognized +algparse -fips -v1 'ike=aes+aes_gcm' + ERROR: IKE encryption algorithm 'aes+aes_gcm' is not recognized diff -Naur libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v2.pfs.txt libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v2.pfs.txt --- libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v2.pfs.txt 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v2.pfs.txt 2019-02-15 16:50:12.778728094 -0500 @@ -1,11 +1,11 @@ algparse -fips -v2 -pfs 'esp' - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 -pfs 'esp=' ERROR: String ended with invalid char, just after "" algparse -fips -v2 -pfs 'esp=aes' - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 -pfs 'esp=aes;modp2048' - AES_CBC-HMAC_SHA1_96-MODP2048 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-MODP2048 algparse -fips -v2 -pfs 'esp=aes-sha1' AES_CBC-HMAC_SHA1_96 algparse -fips -v2 -pfs 'esp=aes-sha1' @@ -13,7 +13,7 @@ algparse -fips -v2 -pfs 'esp=aes-sha1-modp2048' AES_CBC-HMAC_SHA1_96-MODP2048 algparse -fips -v2 -pfs 'esp=aes-128' - AES_CBC_128-HMAC_SHA1_96 + AES_CBC_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 -pfs 'esp=aes-128-sha1' AES_CBC_128-HMAC_SHA1_96 algparse -fips -v2 -pfs 'esp=aes-128-sha1' @@ -41,7 +41,7 @@ algparse -fips -v2 -pfs 'esp=null-sha1' ERROR: ESP encryption algorithm 'null' is not supported algparse -fips -v2 -pfs 'esp=aes_cbc' - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 -pfs 'esp=aes-sha' AES_CBC-HMAC_SHA1_96 algparse -fips -v2 -pfs 'esp=aes-sha1' @@ -57,7 +57,7 @@ algparse -fips -v2 -pfs 'esp=aes128-sha1' AES_CBC_128-HMAC_SHA1_96 algparse -fips -v2 -pfs 'esp=aes128-aes_xcbc' - AES_CBC_128-AES_XCBC_96 + ERROR: ESP integrity algorithm 'aes_xcbc' is not supported algparse -fips -v2 -pfs 'esp=aes192-sha1' AES_CBC_192-HMAC_SHA1_96 algparse -fips -v2 -pfs 'esp=aes256-sha1' @@ -181,15 +181,15 @@ algparse -fips -v2 -pfs 'esp=aes_gcm_16_256-null' AES_GCM_16_256-NONE algparse -fips -v2 -pfs 'esp=aes_ctr' - AES_CTR-HMAC_SHA1_96 + AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 -pfs 'esp=aesctr' - AES_CTR-HMAC_SHA1_96 + AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 -pfs 'esp=aes_ctr128' - AES_CTR_128-HMAC_SHA1_96 + AES_CTR_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 -pfs 'esp=aes_ctr192' - AES_CTR_192-HMAC_SHA1_96 + AES_CTR_192-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 -pfs 'esp=aes_ctr256' - AES_CTR_256-HMAC_SHA1_96 + AES_CTR_256-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 -pfs 'esp=serpent' ERROR: ESP encryption algorithm 'serpent' is not supported algparse -fips -v2 -pfs 'esp=twofish' @@ -197,7 +197,7 @@ algparse -fips -v2 -pfs 'esp=camellia_cbc_256-hmac_sha2_512_256;modp8192' ERROR: ESP encryption algorithm 'camellia_cbc_256' is not supported algparse -fips -v2 -pfs 'esp=null_auth_aes_gmac_256-null;modp8192' - ERROR: ESP encryption algorithm 'null_auth_aes_gmac_256' is not supported + NULL_AUTH_AES_GMAC_256-NONE-MODP8192 algparse -fips -v2 -pfs 'esp=3des-sha1;modp8192' 3DES_CBC-HMAC_SHA1_96-MODP8192 algparse -fips -v2 -pfs 'esp=3des-sha1-modp8192' @@ -210,12 +210,12 @@ algparse -fips -v2 -pfs 'esp=aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192' AES_CBC-HMAC_SHA1_96-MODP8192 algparse -fips -v2 -pfs 'esp=aes;none' - AES_CBC-HMAC_SHA1_96-NONE + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-NONE algparse -fips -v2 -pfs 'esp=aes;none,aes' ERROR: either all or no ESP proposals should specify DH algparse -fips -v2 -pfs 'esp=aes;none,aes;modp2048' - AES_CBC-HMAC_SHA1_96-NONE - AES_CBC-HMAC_SHA1_96-MODP2048 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-NONE + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128-MODP2048 algparse -fips -v2 -pfs 'esp=aes-sha1-none' AES_CBC-HMAC_SHA1_96-NONE algparse -fips -v2 -pfs 'esp=aes-sha1;none' @@ -293,7 +293,7 @@ algparse -fips -v2 -pfs 'esp=3des-sha1-modp8192,3des-sha2-modp2048' ERROR: more than one IKEv2 ESP DH algorithm (MODP8192, MODP2048) requires unimplemented CHILD_SA INVALID_KE algparse -fips -v2 -pfs 'ah' - HMAC_SHA1_96 + HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 -pfs 'ah=' ERROR: String ended with invalid char, just after "" algparse -fips -v2 -pfs 'ah=md5' @@ -319,7 +319,7 @@ algparse -fips -v2 -pfs 'ah=sha2_512' HMAC_SHA2_512_256 algparse -fips -v2 -pfs 'ah=aes_xcbc' - AES_XCBC_96 + ERROR: AH integrity algorithm 'aes_xcbc' is not supported algparse -fips -v2 -pfs 'ah=sha2-none' HMAC_SHA2_256_128-NONE algparse -fips -v2 -pfs 'ah=sha2;none' @@ -345,32 +345,23 @@ algparse -fips -v2 -pfs 'ah=ripemd' ERROR: AH integrity algorithm 'ripemd' is not recognized algparse -fips -v2 -pfs 'ike' - AES_CBC-HMAC_SHA2_256-MODP2048 - AES_CBC-HMAC_SHA2_512-MODP2048 - AES_CBC-HMAC_SHA1-MODP2048 - 3DES_CBC-HMAC_SHA2_256-MODP2048 - 3DES_CBC-HMAC_SHA2_512-MODP2048 - 3DES_CBC-HMAC_SHA1-MODP2048 + AES_CBC+3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -fips -v2 -pfs 'ike=' ERROR: String ended with invalid char, just after "" algparse -fips -v2 -pfs 'ike=3des-sha1' - 3DES_CBC-HMAC_SHA1-MODP2048 + 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -fips -v2 -pfs 'ike=3des-sha1' - 3DES_CBC-HMAC_SHA1-MODP2048 + 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -fips -v2 -pfs 'ike=3des-sha1;modp1536' ERROR: IKE DH algorithm 'modp1536' is not supported algparse -fips -v2 -pfs 'ike=3des;dh21' - 3DES_CBC-HMAC_SHA2_256-DH21 - 3DES_CBC-HMAC_SHA2_512-DH21 - 3DES_CBC-HMAC_SHA1-DH21 + 3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-DH21 algparse -fips -v2 -pfs 'ike=3des-sha1;dh21' 3DES_CBC-HMAC_SHA1-DH21 algparse -fips -v2 -pfs 'ike=3des-sha1-ecp_521' 3DES_CBC-HMAC_SHA1-DH21 algparse -fips -v2 -pfs 'ike=aes_gcm' - AES_GCM_16-HMAC_SHA2_256-MODP2048 - AES_GCM_16-HMAC_SHA2_512-MODP2048 - AES_GCM_16-HMAC_SHA1-MODP2048 + AES_GCM_16-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -fips -v2 -pfs 'ike=aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192' AES_CBC-HMAC_SHA1-MODP8192 algparse -fips -v2 -pfs 'ike=aes;none' @@ -381,3 +372,10 @@ ERROR: IKE PRF algorithm 'id2' is not recognized algparse -fips -v2 -pfs 'ike=aes_ccm' ERROR: IKE encryption algorithm 'aes_ccm' is not supported +algparse -fips -v2 -pfs 'ike=aes_gcm-sha1-none-modp2048' + ERROR: 'modp2048' unexpected +algparse -fips -v2 -pfs 'ike=aes_gcm+aes_gcm-sha1-none-modp2048' + WARNING: discarding duplicate algorithm 'aes_gcm_16' + ERROR: 'modp2048' unexpected +algparse -fips -v2 -pfs 'ike=aes+aes_gcm' + ERROR: AEAD and non-AEAD IKE encryption algorithm can not be combined diff -Naur libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v2.txt libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v2.txt --- libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v2.txt 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v2.txt 2019-02-15 16:50:12.778728094 -0500 @@ -1,12 +1,12 @@ algparse -fips -v2 'esp' - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 'esp=' ERROR: String ended with invalid char, just after "" algparse -fips -v2 'esp=aes' - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 'esp=aes;modp2048' WARNING: ignoring ESP DH algorithm MODP2048 as PFS policy is disabled - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 'esp=aes-sha1' AES_CBC-HMAC_SHA1_96 algparse -fips -v2 'esp=aes-sha1' @@ -15,7 +15,7 @@ WARNING: ignoring ESP DH algorithm MODP2048 as PFS policy is disabled AES_CBC-HMAC_SHA1_96 algparse -fips -v2 'esp=aes-128' - AES_CBC_128-HMAC_SHA1_96 + AES_CBC_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 'esp=aes-128-sha1' AES_CBC_128-HMAC_SHA1_96 algparse -fips -v2 'esp=aes-128-sha1' @@ -47,7 +47,7 @@ algparse -fips -v2 'esp=null-sha1' ERROR: ESP encryption algorithm 'null' is not supported algparse -fips -v2 'esp=aes_cbc' - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 'esp=aes-sha' AES_CBC-HMAC_SHA1_96 algparse -fips -v2 'esp=aes-sha1' @@ -63,7 +63,7 @@ algparse -fips -v2 'esp=aes128-sha1' AES_CBC_128-HMAC_SHA1_96 algparse -fips -v2 'esp=aes128-aes_xcbc' - AES_CBC_128-AES_XCBC_96 + ERROR: ESP integrity algorithm 'aes_xcbc' is not supported algparse -fips -v2 'esp=aes192-sha1' AES_CBC_192-HMAC_SHA1_96 algparse -fips -v2 'esp=aes256-sha1' @@ -187,15 +187,15 @@ algparse -fips -v2 'esp=aes_gcm_16_256-null' AES_GCM_16_256-NONE algparse -fips -v2 'esp=aes_ctr' - AES_CTR-HMAC_SHA1_96 + AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 'esp=aesctr' - AES_CTR-HMAC_SHA1_96 + AES_CTR-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 'esp=aes_ctr128' - AES_CTR_128-HMAC_SHA1_96 + AES_CTR_128-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 'esp=aes_ctr192' - AES_CTR_192-HMAC_SHA1_96 + AES_CTR_192-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 'esp=aes_ctr256' - AES_CTR_256-HMAC_SHA1_96 + AES_CTR_256-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 'esp=serpent' ERROR: ESP encryption algorithm 'serpent' is not supported algparse -fips -v2 'esp=twofish' @@ -203,7 +203,8 @@ algparse -fips -v2 'esp=camellia_cbc_256-hmac_sha2_512_256;modp8192' ERROR: ESP encryption algorithm 'camellia_cbc_256' is not supported algparse -fips -v2 'esp=null_auth_aes_gmac_256-null;modp8192' - ERROR: ESP encryption algorithm 'null_auth_aes_gmac_256' is not supported + WARNING: ignoring ESP DH algorithm MODP8192 as PFS policy is disabled + NULL_AUTH_AES_GMAC_256-NONE algparse -fips -v2 'esp=3des-sha1;modp8192' WARNING: ignoring ESP DH algorithm MODP8192 as PFS policy is disabled 3DES_CBC-HMAC_SHA1_96 @@ -224,16 +225,16 @@ AES_CBC-HMAC_SHA1_96 algparse -fips -v2 'esp=aes;none' WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 'esp=aes;none,aes' WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled - AES_CBC-HMAC_SHA1_96 - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 'esp=aes;none,aes;modp2048' WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled WARNING: ignoring ESP DH algorithm MODP2048 as PFS policy is disabled - AES_CBC-HMAC_SHA1_96 - AES_CBC-HMAC_SHA1_96 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 + AES_CBC-HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 'esp=aes-sha1-none' WARNING: ignoring redundant ESP DH algorithm NONE as PFS policy is disabled AES_CBC-HMAC_SHA1_96 @@ -328,7 +329,7 @@ 3DES_CBC-HMAC_SHA1_96 3DES_CBC-HMAC_SHA2_256_128 algparse -fips -v2 'ah' - HMAC_SHA1_96 + HMAC_SHA2_512_256+HMAC_SHA2_256_128 algparse -fips -v2 'ah=' ERROR: String ended with invalid char, just after "" algparse -fips -v2 'ah=md5' @@ -355,7 +356,7 @@ algparse -fips -v2 'ah=sha2_512' HMAC_SHA2_512_256 algparse -fips -v2 'ah=aes_xcbc' - AES_XCBC_96 + ERROR: AH integrity algorithm 'aes_xcbc' is not supported algparse -fips -v2 'ah=sha2-none' WARNING: ignoring redundant AH DH algorithm NONE as PFS policy is disabled HMAC_SHA2_256_128 @@ -384,32 +385,23 @@ algparse -fips -v2 'ah=ripemd' ERROR: AH integrity algorithm 'ripemd' is not recognized algparse -fips -v2 'ike' - AES_CBC-HMAC_SHA2_256-MODP2048 - AES_CBC-HMAC_SHA2_512-MODP2048 - AES_CBC-HMAC_SHA1-MODP2048 - 3DES_CBC-HMAC_SHA2_256-MODP2048 - 3DES_CBC-HMAC_SHA2_512-MODP2048 - 3DES_CBC-HMAC_SHA1-MODP2048 + AES_CBC+3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -fips -v2 'ike=' ERROR: String ended with invalid char, just after "" algparse -fips -v2 'ike=3des-sha1' - 3DES_CBC-HMAC_SHA1-MODP2048 + 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -fips -v2 'ike=3des-sha1' - 3DES_CBC-HMAC_SHA1-MODP2048 + 3DES_CBC-HMAC_SHA1-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -fips -v2 'ike=3des-sha1;modp1536' ERROR: IKE DH algorithm 'modp1536' is not supported algparse -fips -v2 'ike=3des;dh21' - 3DES_CBC-HMAC_SHA2_256-DH21 - 3DES_CBC-HMAC_SHA2_512-DH21 - 3DES_CBC-HMAC_SHA1-DH21 + 3DES_CBC-HMAC_SHA2_512+HMAC_SHA2_256-DH21 algparse -fips -v2 'ike=3des-sha1;dh21' 3DES_CBC-HMAC_SHA1-DH21 algparse -fips -v2 'ike=3des-sha1-ecp_521' 3DES_CBC-HMAC_SHA1-DH21 algparse -fips -v2 'ike=aes_gcm' - AES_GCM_16-HMAC_SHA2_256-MODP2048 - AES_GCM_16-HMAC_SHA2_512-MODP2048 - AES_GCM_16-HMAC_SHA1-MODP2048 + AES_GCM_16-HMAC_SHA2_512+HMAC_SHA2_256-MODP2048+MODP3072+MODP4096+MODP8192+DH19+DH20+DH21+DH31 algparse -fips -v2 'ike=aes-sha1-modp8192,aes-sha1-modp8192,aes-sha1-modp8192' AES_CBC-HMAC_SHA1-MODP8192 algparse -fips -v2 'ike=aes;none' @@ -420,3 +412,10 @@ ERROR: IKE PRF algorithm 'id2' is not recognized algparse -fips -v2 'ike=aes_ccm' ERROR: IKE encryption algorithm 'aes_ccm' is not supported +algparse -fips -v2 'ike=aes_gcm-sha1-none-modp2048' + ERROR: 'modp2048' unexpected +algparse -fips -v2 'ike=aes_gcm+aes_gcm-sha1-none-modp2048' + WARNING: discarding duplicate algorithm 'aes_gcm_16' + ERROR: 'modp2048' unexpected +algparse -fips -v2 'ike=aes+aes_gcm' + ERROR: AEAD and non-AEAD IKE encryption algorithm can not be combined diff -Naur libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v.txt libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v.txt --- libreswan-3.27-orig/testing/pluto/algparse-02-fips/algparse.v.txt 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/testing/pluto/algparse-02-fips/algparse.v.txt 2019-02-15 16:32:29.006835593 -0500 @@ -3,13 +3,14 @@ algparse: Encryption algorithm SERPENT_CBC disabled; not FIPS compliant algparse: Encryption algorithm TWOFISH_CBC disabled; not FIPS compliant algparse: Encryption algorithm TWOFISH_SSH disabled; not FIPS compliant -algparse: Encryption algorithm NULL_AUTH_AES_GMAC disabled; not FIPS compliant algparse: Encryption algorithm NULL disabled; not FIPS compliant algparse: Encryption algorithm CHACHA20_POLY1305 disabled; not FIPS compliant algparse: Hash algorithm MD5 disabled; not FIPS compliant algparse: PRF algorithm HMAC_MD5 disabled; not FIPS compliant +algparse: PRF algorithm AES_XCBC disabled; not FIPS compliant algparse: Integrity algorithm HMAC_MD5_96 disabled; not FIPS compliant algparse: Integrity algorithm HMAC_SHA2_256_TRUNCBUG disabled; not FIPS compliant +algparse: Integrity algorithm AES_XCBC_96 disabled; not FIPS compliant algparse: DH algorithm MODP1024 disabled; not FIPS compliant algparse: DH algorithm MODP1536 disabled; not FIPS compliant algparse: DH algorithm DH31 disabled; not FIPS compliant @@ -23,6 +24,7 @@ algparse: AES_GCM_8 IKEv1: ESP IKEv2: IKE ESP FIPS {256,192,*128} aes_gcm_a algparse: AES_CTR IKEv1: IKE ESP IKEv2: IKE ESP FIPS {256,192,*128} aesctr algparse: AES_CBC IKEv1: IKE ESP IKEv2: IKE ESP FIPS {256,192,*128} aes +algparse: NULL_AUTH_AES_GMAC IKEv1: ESP IKEv2: ESP FIPS {256,192,*128} aes_gmac algparse: FIPS Hash algorithms: algparse: SHA1 IKEv1: IKE IKEv2: FIPS sha algparse: SHA2_256 IKEv1: IKE IKEv2: FIPS sha2, sha256 @@ -33,15 +35,13 @@ algparse: HMAC_SHA2_256 IKEv1: IKE IKEv2: IKE FIPS sha2, sha256, sha2_256 algparse: HMAC_SHA2_384 IKEv1: IKE IKEv2: IKE FIPS sha384, sha2_384 algparse: HMAC_SHA2_512 IKEv1: IKE IKEv2: IKE FIPS sha512, sha2_512 -algparse: AES_XCBC IKEv1: IKEv2: IKE FIPS aes128_xcbc algparse: FIPS Integrity algorithms: algparse: HMAC_SHA1_96 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha, sha1, sha1_96, hmac_sha1 -algparse: HMAC_SHA2_512_256 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha512, sha2_512, hmac_sha2_512 -algparse: HMAC_SHA2_384_192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha384, sha2_384, hmac_sha2_384 -algparse: HMAC_SHA2_256_128 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha2, sha256, sha2_256, hmac_sha2_256 -algparse: AES_XCBC_96 IKEv1: ESP AH IKEv2: IKE ESP AH FIPS aes_xcbc, aes128_xcbc, aes128_xcbc_96 +algparse: HMAC_SHA2_512_256 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha512, sha2_512, sha2_512_256, hmac_sha2_512 +algparse: HMAC_SHA2_384_192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha384, sha2_384, sha2_384_192, hmac_sha2_384 +algparse: HMAC_SHA2_256_128 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha2, sha256, sha2_256, sha2_256_128, hmac_sha2_256 algparse: AES_CMAC_96 IKEv1: ESP AH IKEv2: ESP AH FIPS aes_cmac -algparse: NONE IKEv1: ESP IKEv2: ESP FIPS null +algparse: NONE IKEv1: ESP IKEv2: IKE ESP FIPS null algparse: FIPS DH algorithms: algparse: NONE IKEv1: IKEv2: IKE ESP AH FIPS null, dh0 algparse: MODP2048 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh14 @@ -49,7 +49,7 @@ algparse: MODP4096 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh16 algparse: MODP6144 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh17 algparse: MODP8192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS dh18 -algparse: DH19 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_256 -algparse: DH20 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_384 -algparse: DH21 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_521 +algparse: DH19 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_256, ecp256 +algparse: DH20 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_384, ecp384 +algparse: DH21 IKEv1: IKE IKEv2: IKE ESP AH FIPS ecp_521, ecp521 algparse: leak detective found no leaks diff -Naur libreswan-3.27-orig/testing/pluto/algparse-02-fips/west.conf libreswan-3.27/testing/pluto/algparse-02-fips/west.conf --- libreswan-3.27-orig/testing/pluto/algparse-02-fips/west.conf 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/testing/pluto/algparse-02-fips/west.conf 2019-02-15 16:32:29.006835593 -0500 @@ -10,4 +10,7 @@ protostack=netkey plutodebug=all +conn %default + ikev2=no + include /testing/baseconfigs/all/etc/ipsec.d/ipsec.conf.common diff -Naur libreswan-3.27-orig/testing/pluto/algparse-02-fips/west.console.txt libreswan-3.27/testing/pluto/algparse-02-fips/west.console.txt --- libreswan-3.27-orig/testing/pluto/algparse-02-fips/west.console.txt 2018-10-07 22:52:09.000000000 -0400 +++ libreswan-3.27/testing/pluto/algparse-02-fips/west.console.txt 2019-02-15 16:32:29.006835593 -0500 @@ -7,8 +7,6 @@ ../bin/algparse.sh PATH/libexec/ipsec/algparse algparse*.txt PATH/libexec/ipsec/algparse -v1 -pfs -t # algparse.v1.pfs.txt PATH/libexec/ipsec/algparse -v1 -t # algparse.v1.txt -PATH/libexec/ipsec/algparse -v1 -v2 -pfs -t # algparse.v1.v2.pfs.txt -PATH/libexec/ipsec/algparse -v1 -v2 -t # algparse.v1.v2.txt PATH/libexec/ipsec/algparse -v2 -pfs -t # algparse.v2.pfs.txt PATH/libexec/ipsec/algparse -v2 -t # algparse.v2.txt PATH/libexec/ipsec/algparse -v # algparse.v.txt @@ -50,6 +48,7 @@ AES_GCM_8 IKEv1: ESP IKEv2: IKE ESP FIPS {256,192,*128} aes_gcm_a AES_CTR IKEv1: IKE ESP IKEv2: IKE ESP FIPS {256,192,*128} aesctr AES_CBC IKEv1: IKE ESP IKEv2: IKE ESP FIPS {256,192,*128} aes + NULL_AUTH_AES_GMAC IKEv1: ESP IKEv2: ESP FIPS {256,192,*128} aes_gmac FIPS Hash algorithms: SHA1 IKEv1: IKE IKEv2: FIPS sha SHA2_256 IKEv1: IKE IKEv2: FIPS sha2, sha256 @@ -60,13 +59,11 @@ HMAC_SHA2_256 IKEv1: IKE IKEv2: IKE FIPS sha2, sha256, sha2_256 HMAC_SHA2_384 IKEv1: IKE IKEv2: IKE FIPS sha384, sha2_384 HMAC_SHA2_512 IKEv1: IKE IKEv2: IKE FIPS sha512, sha2_512 - AES_XCBC IKEv1: IKEv2: IKE FIPS aes128_xcbc FIPS Integrity algorithms: HMAC_SHA1_96 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha, sha1, sha1_96, hmac_sha1 HMAC_SHA2_512_256 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha512, sha2_512, hmac_sha2_512 HMAC_SHA2_384_192 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha384, sha2_384, hmac_sha2_384 HMAC_SHA2_256_128 IKEv1: IKE ESP AH IKEv2: IKE ESP AH FIPS sha2, sha256, sha2_256, hmac_sha2_256 - AES_XCBC_96 IKEv1: ESP AH IKEv2: IKE ESP AH FIPS aes_xcbc, aes128_xcbc, aes128_xcbc_96 AES_CMAC_96 IKEv1: ESP AH IKEv2: ESP AH FIPS aes_cmac NONE IKEv1: ESP IKEv2: ESP FIPS null FIPS DH algorithms: