commit b4adefb5e49f4ffbb3da57b715b81b90a865eb1c Author: Paul Wouters Date: Fri Jan 10 12:38:28 2014 -0500 SECURITY: patch for CVE-2013-6467 dereferencing missing IKEv2 payloads This patch introduces the same state machine logic from IKEv1, where processor functions cannot be called unless the mandatory payloads are present. Most of this work was done by D. Hugh Redelmeier. diff --git a/include/ietf_constants.h b/include/ietf_constants.h index afb897d..ccf0685 100644 --- a/include/ietf_constants.h +++ b/include/ietf_constants.h @@ -408,17 +408,17 @@ enum next_payload_types_ikev1 { ISAKMP_NEXT_NATOA_DRAFTS = 131, /* NAT-Traversal: NAT-OA (drafts) */ /* Cisco/Microsoft proprietary IKE fragmentation */ ISAKMP_NEXT_IKE_FRAGMENTATION = 132, - ISAKMP_NEXT_ROOF = 254, /* roof on payload types */ + ISAKMP_NEXT_ROOF, /* roof on payload types */ }; enum ikev2_last_proposal { - /* if there is a next proposal, then the lp needs to be set right*/ + /* if there is a next proposal, then the lp needs to be set right */ v2_PROPOSAL_LAST = 0, /* matches IKEv1 ISAKMP_NEXT_NONE by design */ v2_PROPOSAL_NON_LAST = 2 /* matches IKEv1 ISAKMP_NEXT_P by design */ }; enum ikev2_last_transform { - /* if there is a next transform, then the lt needs to be set right*/ + /* if there is a next transform, then the lt needs to be set right */ v2_TRANSFORM_LAST = 0, /* matches IKEv1 ISAKMP_NEXT_NONE by design */ v2_TRANSFORM_NON_LAST = 3 /* matches IKEv1 ISAKMP_NEXT_T by design */ }; @@ -446,9 +446,11 @@ enum next_payload_types_ikev2 { /* 128 - 255 Private Use */ /* Cisco/Microsoft proprietary IKE fragmentation - private use for libreswan */ ISAKMP_NEXT_v2IKE_FRAGMENTATION = 132, - ISAKMP_NEXT_v2ROOF = 254, /* roof on payload types - keep same as v1 */ + ISAKMP_NEXT_v2ROOF, /* roof on payload types */ }; +#define ISAKMP_v2PAYLOAD_TYPE_BASE ISAKMP_NEXT_v2SA /* lowest value of a v2 payload type */ + /* * These values are to be used within the Type field of an Attribute (14) * ISAKMP payload. diff --git a/include/names_constant.h b/include/names_constant.h index ef807e0..15e8a87 100644 --- a/include/names_constant.h +++ b/include/names_constant.h @@ -35,6 +35,7 @@ extern enum_names oakley_lifetime_names; extern enum_names version_names; extern enum_names doi_names; extern enum_names payload_names_ikev1; +extern const char *const payload_name_ikev2_main[]; extern enum_names payload_names_ikev2; extern enum_names ikev2_last_proposal_desc; extern enum_names ikev2_last_transform_desc; diff --git a/include/packet.h b/include/packet.h index d62ff7a..f961ced 100644 --- a/include/packet.h +++ b/include/packet.h @@ -695,9 +695,10 @@ extern struct_desc isakmp_ikefrag_desc; * on the mode. Since this is table only used for top-level payloads, * Proposal and Transform payloads need not be handled. * That leaves only Identification payloads as a problem. - * We make all these entries NULL + * We make all these entries NULL. + * ??? is there a good reason for these two things to be in one table? */ -extern struct_desc *const payload_descs[ISAKMP_NEXT_ROOF]; +extern const struct_desc *payload_desc(unsigned p); /* * IKEv2 structures diff --git a/include/pluto_constants.h b/include/pluto_constants.h index b398811..cbb40bf 100644 --- a/include/pluto_constants.h +++ b/include/pluto_constants.h @@ -210,6 +210,7 @@ typedef enum { #define IMPAIR_MINOR_VERSION_BUMP LELEM(IMPAIR0 + 8) /* cause pluto to send an IKE minor version that's higher then we support. */ #define IMPAIR_RETRANSMITS LELEM(IMPAIR0 + 9) /* cause pluto to never retransmit */ #define IMPAIR_SEND_BOGUS_ISAKMP_FLAG LELEM(IMPAIR0 + 10) /* causes pluto to set a RESERVED ISAKMP flag to test ignoring/zeroing it */ +#define IMPAIR_SEND_IKEv2_KE LELEM(IMPAIR0 + 11) /* causes pluto to omit sending the KE payload in IKEv2 */ #define DBG_NONE 0 /* no options on, including impairments */ #define DBG_ALL LRANGES(DBG_RAW, DBG_OPPOINFO) /* all logging options on EXCEPT DBG_PRIVATE and DBG_WHACKWATCH */ diff --git a/lib/libswan/constants.c b/lib/libswan/constants.c index 2ccd267..4c4b4ce 100644 --- a/lib/libswan/constants.c +++ b/lib/libswan/constants.c @@ -117,6 +117,7 @@ const char *const debug_bit_names[] = { "impair-minor-version-bump", /* 29 */ "impair-retransmits", /* 30 */ "impair-send-bogus-isakmp-flag", /* 31 */ + "impair-send-ikev2-ke", /* 32 */ NULL /* termination for bitnamesof() */ }; @@ -179,7 +180,8 @@ static const char *const payload_name_ikev2[] = { "ISAKMP_NEXT_v2NONE", /* same for IKEv1 */ }; -static const char *const payload_name_ikev2_main[] = { +/* dual-use: for enum_name and for bitnamesof */ +const char *const payload_name_ikev2_main[] = { "ISAKMP_NEXT_v2SA", /* 33 */ "ISAKMP_NEXT_v2KE", "ISAKMP_NEXT_v2IDi", @@ -196,6 +198,7 @@ static const char *const payload_name_ikev2_main[] = { "ISAKMP_NEXT_v2E", "ISAKMP_NEXT_v2CP", "ISAKMP_NEXT_v2EAP", + NULL /* termination for bitnamesof() */ }; static const char *const payload_name_ikev2_private_use[] = { diff --git a/programs/pluto/demux.h b/programs/pluto/demux.h index 916a83a..5595b1d 100644 --- a/programs/pluto/demux.h +++ b/programs/pluto/demux.h @@ -87,8 +87,15 @@ struct msg_digest { # define PAYLIMIT 30 struct payload_digest digest[PAYLIMIT], - *digest_roof, - *chain[ISAKMP_NEXT_ROOF]; + *digest_roof; + /* ??? It seems unlikely that chain will need to store payloads numbered as high as these. + * ISAKMP_NEXT_NATD_DRAFTS, ISAKMP_NEXT_NATOA_DRAFTS and + * ISAKMP_NEXT_IKE_FRAGMENTATION/ISAKMP_NEXT_v2IKE_FRAGMENTATION + * probably make no sense here. + * Also a v1 and a v2 version might make sense and be smaller. + */ + struct payload_digest + *chain[(unsigned)ISAKMP_NEXT_ROOF>(unsigned)ISAKMP_NEXT_v2ROOF ? ISAKMP_NEXT_ROOF : ISAKMP_NEXT_v2ROOF]; struct isakmp_quirks quirks; }; diff --git a/programs/pluto/ikev1.c b/programs/pluto/ikev1.c index 97fd74a..75d03b1 100644 --- a/programs/pluto/ikev1.c +++ b/programs/pluto/ikev1.c @@ -227,7 +227,7 @@ static state_transition_fn /* forward declaration */ */ static const struct state_microcode -*ike_microcode_index[STATE_IKE_ROOF - STATE_IKE_FLOOR]; + *ike_microcode_index[STATE_IKE_ROOF - STATE_IKE_FLOOR]; #define PHONY_STATE(X) \ { X, X \ @@ -1870,10 +1870,7 @@ void process_packet_tail(struct msg_digest **mdp) ""; while (np != ISAKMP_NEXT_NONE) { - struct_desc *sd = np < - ISAKMP_NEXT_ROOF ? payload_descs[np] - : - NULL; + struct_desc *sd = payload_desc(np); if (pd == &md->digest[PAYLIMIT]) { loglog(RC_LOG_SERIOUS, @@ -1893,10 +1890,8 @@ void process_packet_tail(struct msg_digest **mdp) switch (np) { case ISAKMP_NEXT_NATD_RFC: case ISAKMP_NEXT_NATOA_RFC: - if ((!st) || - (!(st->hidden_variables. - st_nat_traversal & - NAT_T_WITH_RFC_VALUES))) { + if (st == NULL || + (st->hidden_variables.st_nat_traversal & NAT_T_WITH_RFC_VALUES) == 0) { /* * don't accept NAT-D/NAT-OA reloc directly in message, * unless we're using NAT-T RFC @@ -1913,21 +1908,20 @@ void process_packet_tail(struct msg_digest **mdp) /* payload type is out of range or requires special handling */ switch (np) { case ISAKMP_NEXT_ID: - sd = - (IS_PHASE1(from_state) || - IS_PHASE15(from_state)) ? - &isakmp_identification_desc : & - isakmp_ipsec_identification_desc; + sd = (IS_PHASE1(from_state) || + IS_PHASE15(from_state)) ? + &isakmp_identification_desc : + &isakmp_ipsec_identification_desc; break; case ISAKMP_NEXT_NATD_DRAFTS: np = ISAKMP_NEXT_NATD_RFC; /* NAT-D was a private use type before RFC-3947 */ - sd = payload_descs[np]; + sd = payload_desc(np); break; case ISAKMP_NEXT_NATOA_DRAFTS: np = ISAKMP_NEXT_NATOA_RFC; /* NAT-OA was a private use type before RFC-3947 */ - sd = payload_descs[np]; + sd = payload_desc(np); break; default: @@ -1938,6 +1932,7 @@ void process_packet_tail(struct msg_digest **mdp) SEND_NOTIFICATION(INVALID_PAYLOAD_TYPE); return; } + passert(sd != NULL); } { @@ -2187,7 +2182,7 @@ void process_packet_tail(struct msg_digest **mdp) /* VERIFY that we only accept NAT-D/NAT-OE when they sent us the VID */ if ((md->chain[ISAKMP_NEXT_NATD_RFC] != NULL || md->chain[ISAKMP_NEXT_NATOA_RFC] != NULL) && - !(st->hidden_variables.st_nat_traversal & NAT_T_WITH_RFC_VALUES)) { + (st->hidden_variables.st_nat_traversal & NAT_T_WITH_RFC_VALUES) == 0) { /* * don't accept NAT-D/NAT-OA reloc directly in message, * unless we're using NAT-T RFC diff --git a/programs/pluto/ikev2.c b/programs/pluto/ikev2.c index 86a6b22..c500f54 100644 --- a/programs/pluto/ikev2.c +++ b/programs/pluto/ikev2.c @@ -78,20 +78,18 @@ struct state_v2_microcode { enum state_kind state, next_state; enum isakmp_xchg_types recv_type; lset_t flags; - lset_t req_payloads; /* required payloads (allows just one) */ - lset_t opt_payloads; /* optional payloads (any mumber) */ + lset_t req_clear_payloads; /* required unencrypted payloads (allows just one) for received packet */ + lset_t opt_clear_payloads; /* optional unencrypted payloads (none or one) for received packet */ + lset_t req_enc_payloads; /* required encrypted payloads (allows just one) for received packet */ + lset_t opt_enc_payloads; /* optional encrypted payloads (none or one) for received packet */ enum event_type timeout_event; state_transition_fn *processor; }; enum smf2_flags { SMF2_INITIATOR = LELEM(1), - SMF2_RESPONDER = 0, - - SMF2_STATENEEDED=LELEM(2), - SMF2_NEWSTATE = 0, - - SMF2_REPLY = LELEM(3), + SMF2_STATENEEDED = LELEM(2), + SMF2_REPLY = LELEM(3), }; /* @@ -130,44 +128,144 @@ enum smf2_flags { * */ -/* it is not clear how the flags will be used yet, if at all */ +/* + * From RFC 5996 syntax: [optional] and {encrypted} + * + * Initiator Responder + * ------------------------------------------------------------------- + * HDR, SAi1, KEi, Ni --> + * <-- HDR, SAr1, KEr, Nr, [CERTREQ] + * + * HDR, SK {IDi, [CERT,] [CERTREQ,] + * [IDr,] AUTH, SAi2, + * TSi, TSr} --> + * <-- HDR, SK {IDr, [CERT,] AUTH, + * SAr2, TSi, TSr} + * [Parent SA established] + * + * HDR, SK {SA, Ni, [KEi], + * TSi, TSr} --> + * + * <-- HDR, SK {SA, Nr, [KEr], + * TSi, TSr} + * [Child SA established] + * + */ + +/* Short forms for building payload type sets */ + +#define PT(n) ISAKMP_NEXT_v2 ## n +#define P(n) LELEM(PT(n) - ISAKMP_v2PAYLOAD_TYPE_BASE) + +/* From RFC 5996: + * + * 3.10 "Notify Payload": N payload may appear in any message + * ??? should encryption be required? + * + * 3.11 "Delete Payload": multiple D payloads may appear in an + * Informational exchange + * + * 3.12 "Vendor ID Payload": (multiple) may appear in any message + * ??? should encryption be required? + * + * 3.15 "Configuration Payload": + * 1.4 "The INFORMATIONAL Exchange": (multiple) Configuration Payloads + * may appear in an Informational exchange + * 2.19 "Requesting an Internal Address on a Remote Network": + * In all cases, the CP payload MUST be inserted before the SA payload. + * In variations of the protocol where there are multiple IKE_AUTH + * exchanges, the CP payloads MUST be inserted in the messages + * containing the SA payloads. + */ + +static const lset_t everywhere_payloads = P(N) | P(V); /* can appear in any packet */ +static const lset_t repeatable_payloads = P(N) | P(D) | P(CP) | P(V); /* if one can appear, many can appear */ -static const struct state_v2_microcode v2_state_microcode_table[] = { +/* microcode to parent first initiator state: not associated with an input packet */ +const struct state_v2_microcode ikev2_parent_firststate_microcode = + /* no state: --> I1 + * HDR, SAi1, KEi, Ni --> + */ { .state = STATE_UNDEFINED, .next_state = STATE_PARENT_I1, .flags = SMF2_INITIATOR, - .processor = NULL, }, + .processor = NULL, }; + +/* microcode for input packet processing */ +static const struct state_v2_microcode v2_state_microcode_table[] = { + /* STATE_PARENT_I1: R1 --> I2 + * <-- HDR, SAr1, KEr, Nr, [CERTREQ] + * HDR, SK {IDi, [CERT,] [CERTREQ,] + * [IDr,] AUTH, SAi2, + * TSi, TSr} --> + */ { .state = STATE_PARENT_I1, .next_state = STATE_PARENT_I2, .flags = SMF2_INITIATOR | SMF2_STATENEEDED | SMF2_REPLY, + .req_clear_payloads = P(SA) | P(KE) | P(Nr), + .opt_clear_payloads = P(CERTREQ), .processor = ikev2parent_inR1outI2, .recv_type = ISAKMP_v2_SA_INIT, }, + /* STATE_PARENT_I2: R2 --> I3 + * <-- HDR, SK {IDr, [CERT,] AUTH, + * SAr2, TSi, TSr} + * [Parent SA established] + */ { .state = STATE_PARENT_I2, .next_state = STATE_PARENT_I3, .flags = SMF2_INITIATOR | SMF2_STATENEEDED, + .req_clear_payloads = P(E), + .req_enc_payloads = P(IDr) | P(AUTH) | P(SA) | P(TSi) | P(TSr), + .opt_enc_payloads = P(CERT), .processor = ikev2parent_inR2, .recv_type = ISAKMP_v2_AUTH, .timeout_event = EVENT_SA_REPLACE, }, + /* no state: none I1 --> R1 + * <-- HDR, SAi1, KEi, Ni + * HDR, SAr1, KEr, Nr, [CERTREQ] --> + */ { .state = STATE_UNDEFINED, .next_state = STATE_PARENT_R1, - .flags = SMF2_RESPONDER | SMF2_NEWSTATE | SMF2_REPLY, + .flags = /* not SMF2_INITIATOR, not SMF2_STATENEEDED */ SMF2_REPLY, + .req_clear_payloads = P(SA) | P(KE) | P(Ni), .processor = ikev2parent_inI1outR1, .recv_type = ISAKMP_v2_SA_INIT, }, + /* STATE_PARENT_R1: I2 --> R2 + * <-- HDR, SK {IDi, [CERT,] [CERTREQ,] + * [IDr,] AUTH, SAi2, + * TSi, TSr} + * HDR, SK {IDr, [CERT,] AUTH, + * SAr2, TSi, TSr} --> + * + * [Parent SA established] + */ { .state = STATE_PARENT_R1, .next_state = STATE_PARENT_R2, - .flags = SMF2_RESPONDER | SMF2_STATENEEDED | SMF2_REPLY, + .flags = /* not SMF2_INITIATOR */ SMF2_STATENEEDED | SMF2_REPLY, + .req_clear_payloads = P(E), + .req_enc_payloads = P(IDi) | P(AUTH) | P(SA) | P(TSi) | P(TSr), + .opt_enc_payloads = P(CERT) | P(CERTREQ) | P(IDr), .processor = ikev2parent_inI2outR2, .recv_type = ISAKMP_v2_AUTH, .timeout_event = EVENT_SA_REPLACE, }, /* Informational Exchange*/ + + /* RFC 5996 1.4 "The INFORMATIONAL Exchange" + * + * HDR, SK {[N,] [D,] [CP,] ...} --> + * <-- HDR, SK {[N,] [D,] [CP], ...} + */ + { .state = STATE_PARENT_I2, .next_state = STATE_PARENT_I2, .flags = SMF2_STATENEEDED, + .req_clear_payloads = P(E), + .opt_enc_payloads = P(N) | P(D) | P(CP), .processor = process_informational_ikev2, .recv_type = ISAKMP_v2_INFORMATIONAL, }, @@ -175,6 +273,8 @@ static const struct state_v2_microcode v2_state_microcode_table[] = { { .state = STATE_PARENT_R1, .next_state = STATE_PARENT_R1, .flags = SMF2_STATENEEDED, + .req_clear_payloads = P(E), + .opt_enc_payloads = P(N) | P(D) | P(CP), .processor = process_informational_ikev2, .recv_type = ISAKMP_v2_INFORMATIONAL, }, @@ -182,6 +282,8 @@ static const struct state_v2_microcode v2_state_microcode_table[] = { { .state = STATE_PARENT_I3, .next_state = STATE_PARENT_I3, .flags = SMF2_STATENEEDED, + .req_clear_payloads = P(E), + .opt_enc_payloads = P(N) | P(D) | P(CP), .processor = process_informational_ikev2, .recv_type = ISAKMP_v2_INFORMATIONAL, }, @@ -189,6 +291,8 @@ static const struct state_v2_microcode v2_state_microcode_table[] = { { .state = STATE_PARENT_R2, .next_state = STATE_PARENT_R2, .flags = SMF2_STATENEEDED, + .req_clear_payloads = P(E), + .opt_enc_payloads = P(N) | P(D) | P(CP), .processor = process_informational_ikev2, .recv_type = ISAKMP_v2_INFORMATIONAL, }, @@ -196,6 +300,8 @@ static const struct state_v2_microcode v2_state_microcode_table[] = { { .state = STATE_IKESA_DEL, .next_state = STATE_IKESA_DEL, .flags = SMF2_STATENEEDED, + .req_clear_payloads = P(E), + .opt_enc_payloads = P(N) | P(D) | P(CP), .processor = process_informational_ikev2, .recv_type = ISAKMP_v2_INFORMATIONAL, }, @@ -203,40 +309,29 @@ static const struct state_v2_microcode v2_state_microcode_table[] = { { .state = STATE_IKEv2_ROOF } }; -const struct state_v2_microcode *ikev2_parent_firststate() -{ - return &v2_state_microcode_table[0]; -} +#undef P +#undef PT /* * split up an incoming message into payloads */ -stf_status ikev2_process_payloads(struct msg_digest *md, +static stf_status ikev2_process_payloads(struct msg_digest *md, pb_stream *in_pbs, - unsigned int from_state, - unsigned int np) + unsigned int np, + lset_t req_payloads, + lset_t opt_payloads) { struct payload_digest *pd = md->digest_roof; - struct state *st = md->st; - - /* ??? is there any logic in v2 like "needed" in v1? - * How are missing payloads discovered? Reported? - * How about unexpected payloads? - */ - /* lset_t needed = smc->req_payloads; */ + lset_t seen = LEMPTY; - /* zero out the digest descriptors -- might nuke [v2E] digest! */ + /* ??? zero out the digest descriptors -- might nuke ISAKMP_NEXT_v2E digest! */ while (np != ISAKMP_NEXT_v2NONE) { - struct_desc *sd = np < - ISAKMP_NEXT_v2ROOF ? payload_descs[np] : NULL; - int thisp = np; - bool unknown_payload = FALSE; + struct_desc *sd = payload_desc(np); DBG(DBG_CONTROL, DBG_log("Now let's proceed with payload (%s)", - enum_show(&payload_names_ikev2, thisp))); - memset(pd, 0, sizeof(*pd)); + enum_show(&payload_names_ikev2, np))); if (pd == &md->digest[PAYLIMIT]) { loglog(RC_LOG_SERIOUS, @@ -245,70 +340,126 @@ stf_status ikev2_process_payloads(struct msg_digest *md, return STF_FAIL + v2N_INVALID_SYNTAX; } - if (sd == NULL) { - unknown_payload = TRUE; - sd = &ikev2_generic_desc; - } + memset(pd, 0, sizeof(*pd)); /* ??? is this needed? */ - /* why to process an unknown payload*/ - /* critical bit in RFC 4306/5996 is just 1 bit not a byte*/ - /* As per RFC other 7 bits are RESERVED and should be ignored*/ - if (unknown_payload) { - if (pd->payload.v2gen.isag_critical & - ISAKMP_PAYLOAD_CRITICAL) { - /* it was critical */ + if (sd == NULL || np < ISAKMP_v2PAYLOAD_TYPE_BASE) { + /* This payload is unknown to us. + * RFCs 4306 and 5996 2.5 say that if the payload + * has the Critical Bit, we should be upset + * but if it does not, we should just ignore it. + */ + if (!in_struct(&pd->payload, &ikev2_generic_desc, in_pbs, &pd->pbs)) { + loglog(RC_LOG_SERIOUS, "malformed payload in packet"); + return STF_FAIL + v2N_INVALID_SYNTAX; + } + if (pd->payload.v2gen.isag_critical & ISAKMP_PAYLOAD_CRITICAL) { + /* It was critical. + * See RFC 5996 1.5 "Version Numbers and Forward Compatibility" + * ??? we are supposed to send the offending np byte back in the + * notify payload. + */ loglog(RC_LOG_SERIOUS, "critical payload (%s) was not understood. Message dropped.", - enum_show(&payload_names_ikev2, thisp)); - return STF_FATAL; + enum_show(&payload_names_ikev2, np)); + return STF_FAIL + v2N_UNSUPPORTED_CRITICAL_PAYLOAD; } loglog(RC_COMMENT, "non-critical payload ignored because it contains an unknown or" " unexpected payload type (%s) at the outermost level", - enum_show(&payload_names_ikev2, thisp)); + enum_show(&payload_names_ikev2, np)); + np = pd->payload.generic.isag_np; + continue; + } + + passert(np - ISAKMP_v2PAYLOAD_TYPE_BASE < LELEM_ROOF); + + { + lset_t s = LELEM(np - ISAKMP_v2PAYLOAD_TYPE_BASE); + + if (s & seen & ~repeatable_payloads) { + /* improperly repeated payload */ + loglog(RC_LOG_SERIOUS, + "payload (%s) unexpectedly repeated. Message dropped.", + enum_show(&payload_names_ikev2, np)); + return STF_FAIL + v2N_INVALID_SYNTAX; + } + if ((s & (req_payloads | opt_payloads | everywhere_payloads)) == LEMPTY) { + /* unexpected payload */ + loglog(RC_LOG_SERIOUS, + "payload (%s) unexpected. Message dropped.", + enum_show(&payload_names_ikev2, np)); + return STF_FAIL + v2N_INVALID_SYNTAX; + } + seen |= s; } if (!in_struct(&pd->payload, sd, in_pbs, &pd->pbs)) { loglog(RC_LOG_SERIOUS, "malformed payload in packet"); - SEND_NOTIFICATION(v2N_INVALID_SYNTAX); - return STF_FAIL; + return STF_FAIL + v2N_INVALID_SYNTAX; } DBG(DBG_PARSING, DBG_log("processing payload: %s (len=%u)\n", - enum_show(&payload_names_ikev2, thisp), + enum_show(&payload_names_ikev2, np), pd->payload.generic.isag_length)); /* place this payload at the end of the chain for this type */ { struct payload_digest **p; - for (p = &md->chain[thisp]; *p != NULL; + for (p = &md->chain[np]; *p != NULL; p = &(*p)->next) ; *p = pd; pd->next = NULL; } - np = pd->payload.generic.isag_np; - - /* do payload-type specific things that need to be here. */ - switch (thisp) { + switch (np) { case ISAKMP_NEXT_v2E: + /* RFC 5996 2.14 "Encrypted Payload": + * + * Next Payload - The payload type of the + * first embedded payload. Note that this is + * an exception in the standard header format, + * since the Encrypted payload is the last + * payload in the message and therefore the + * Next Payload field would normally be zero. + * But because the content of this payload is + * embedded payloads and there was no natural + * place to put the type of the first one, + * that type is placed here. + */ np = ISAKMP_NEXT_v2NONE; break; - default: /* nothing special */ + + default: + np = pd->payload.generic.isag_np; break; } pd++; } + if (req_payloads & ~seen) { + loglog(RC_LOG_SERIOUS, + "missing payload(s) (%s). Message dropped.", + bitnamesof(payload_name_ikev2_main, req_payloads & ~seen)); + return STF_FAIL + v2N_INVALID_SYNTAX; + } + DBG(DBG_CONTROL, DBG_log("Finished and now at the end of ikev2_process_payload")); md->digest_roof = pd; return STF_OK; } +/* this stub is needed because struct state_v2_microcode is local to this file */ +stf_status ikev2_process_encrypted_payloads(struct msg_digest *md, + pb_stream *in_pbs, + unsigned int np) +{ + return ikev2_process_payloads(md, in_pbs, np, md->svm->req_enc_payloads, md->svm->opt_enc_payloads); +} + /* * process an input packet, possibly generating a reply. * @@ -451,17 +602,13 @@ void process_v2_packet(struct msg_digest **mdp) } if (svm->state != from_state) continue; + if (svm->recv_type != ix) continue; - /* I1 receiving NO_PROPOSAL ended up picking the wrong STATE_UNDEFINED state - Since the wrong state is a responder, we just add a check for initiator, - so we hit STATE_IKEv2_ROOF - */ - /* - if ( ((svm->flags&SMF2_INITIATOR) != 0) != ((md->hdr.isa_flags & ISAKMP_FLAGS_R) != 0) ) - continue; - */ + /* ??? not sure that this is necessary, but it ought to be correct */ + if ( ((svm->flags&SMF2_INITIATOR) != 0) != ((md->hdr.isa_flags & ISAKMP_FLAGS_R) != 0) ) + continue; /* must be the right state */ break; @@ -470,7 +617,7 @@ void process_v2_packet(struct msg_digest **mdp) if (svm->state == STATE_IKEv2_ROOF) { DBG(DBG_CONTROL, DBG_log("ended up with STATE_IKEv2_ROOF")); - /* no useful state */ + /* no useful state microcode entry */ if (md->hdr.isa_flags & ISAKMP_FLAGS_I) { /* must be an initiator message, so we are the responder */ @@ -480,9 +627,14 @@ void process_v2_packet(struct msg_digest **mdp) return; } + md->svm = svm; + md->from_state = from_state; + md->st = st; + { stf_status stf = ikev2_process_payloads(md, &md->message_pbs, - from_state, md->hdr.isa_np); + md->hdr.isa_np, + svm->req_clear_payloads, svm->opt_clear_payloads); DBG(DBG_CONTROL, DBG_log("Finished processing ikev2_process_payloads")); @@ -493,31 +645,16 @@ void process_v2_packet(struct msg_digest **mdp) } } - DBG(DBG_CONTROL, - DBG_log("Now lets proceed with state specific processing")); - DBG(DBG_PARSING, { if (pbs_left(&md->message_pbs) != 0) DBG_log("removing %d bytes of padding", (int) pbs_left(&md->message_pbs)); }); - md->message_pbs.roof = md->message_pbs.cur; + md->message_pbs.roof = md->message_pbs.cur; /* trim padding (not actually legit) */ -#if 0 - /* check that all mandatory payloads appeared */ - if (needed != 0) { - loglog(RC_LOG_SERIOUS, "message for %s is missing payloads %s", - enum_show(&state_names, from_state), - bitnamesof(payload_name_ikev2, needed)); - SEND_NOTIFICATION(v2N_INVALID_SYNTAX); - return; - } -#endif - - md->svm = svm; - md->from_state = from_state; - md->st = st; + DBG(DBG_CONTROL, + DBG_log("Now lets proceed with state specific processing")); complete_v2_state_transition(mdp, (svm->processor)(md)); } @@ -1050,8 +1187,16 @@ void complete_v2_state_transition(struct msg_digest **mdp, v2_notification_t accept_v2_nonce(struct msg_digest *md, chunk_t *dest, const char *name) { - pb_stream *nonce_pbs = &md->chain[ISAKMP_NEXT_v2Ni]->pbs; - size_t len = pbs_left(nonce_pbs); + pb_stream *nonce_pbs; + size_t len; + + if(md->chain[ISAKMP_NEXT_v2Ni] == NULL) { + loglog(RC_LOG_SERIOUS, "missing nonce Ni"); + return v2N_INVALID_SYNTAX; + } + + nonce_pbs = &md->chain[ISAKMP_NEXT_v2Ni]->pbs; + len = pbs_left(nonce_pbs); if (len < MINIMUM_NONCE_SIZE || MAXIMUM_NONCE_SIZE < len) { loglog(RC_LOG_SERIOUS, "%s length not between %d and %d", diff --git a/programs/pluto/ikev2.h b/programs/pluto/ikev2.h index b852754..e261201 100644 --- a/programs/pluto/ikev2.h +++ b/programs/pluto/ikev2.h @@ -41,7 +41,7 @@ extern stf_status ikev2parent_inR1outI2(struct msg_digest *md); extern stf_status ikev2parent_inI2outR2(struct msg_digest *md); extern stf_status ikev2parent_inR2(struct msg_digest *md); -extern const struct state_v2_microcode *ikev2_parent_firststate(void); +extern const struct state_v2_microcode ikev2_parent_firststate_microcode; extern v2_notification_t accept_v2_nonce(struct msg_digest *md, chunk_t *dest, const char *name); @@ -90,13 +90,14 @@ extern void send_v2_notification_from_state(struct state *st, extern void send_v2_notification_from_md(struct msg_digest *md, u_int16_t type, chunk_t *data); -extern stf_status ikev2_process_payloads(struct msg_digest *md, + +extern stf_status ikev2_process_encrypted_payloads(struct msg_digest *md, pb_stream *in_pbs, - unsigned int from_state, unsigned int np); extern bool ikev2_decode_peer_id(struct msg_digest *md, enum phase1_role initiator); + extern void ikev2_log_parentSA(struct state *st); extern bool ikev2_calculate_rsa_sha1(struct state *st, diff --git a/programs/pluto/ikev2_parent.c b/programs/pluto/ikev2_parent.c index 6be7590..f780535 100644 --- a/programs/pluto/ikev2_parent.c +++ b/programs/pluto/ikev2_parent.c @@ -227,7 +227,7 @@ stf_status ikev2parent_outI1(int whack_sock, ke->md = alloc_md(); ke->md->from_state = STATE_IKEv2_BASE; - ke->md->svm = ikev2_parent_firststate(); + ke->md->svm = &ikev2_parent_firststate_microcode; ke->md->st = st; set_suspended(st, ke->md); @@ -411,17 +411,20 @@ static stf_status ikev2_parent_outI1_common(struct msg_digest *md, { u_char *sa_start = md->rbody.cur; + if (st->st_sadb->prop_disj_cnt == 0 || st->st_sadb->prop_disj) st->st_sadb = sa_v2_convert(st->st_sadb); - if (!ikev2_out_sa(&md->rbody, - PROTO_ISAKMP, - st->st_sadb, - st, TRUE, /* parentSA */ + if (!DBGP(IMPAIR_SEND_IKEv2_KE)) { + if (!ikev2_out_sa(&md->rbody, PROTO_ISAKMP, st->st_sadb, st, + TRUE, /* parentSA */ ISAKMP_NEXT_v2KE)) { - libreswan_log("outsa fail"); - reset_cur_state(); - return STF_INTERNAL_ERROR; + libreswan_log("outsa fail"); + reset_cur_state(); + return STF_INTERNAL_ERROR; + } + } else { + libreswan_log("SKIPPED sending KE payload because impair-send-ikev2-ke was set"); } /* save initiator SA for later HASH */ if (st->st_p1isa.ptr == NULL) { /* no leak! (MUST be first time) */ @@ -513,6 +516,12 @@ static stf_status ikev2_parent_outI1_common(struct msg_digest *md, * * */ + +/* no state: none I1 --> R1 + * <-- HDR, SAi1, KEi, Ni + * HDR, SAr1, KEr, Nr, [CERTREQ] --> + */ + static void ikev2_parent_inI1outR1_continue(struct pluto_crypto_req_cont *pcrc, struct pluto_crypto_req *r, err_t ugh); @@ -865,7 +874,14 @@ static stf_status ikev2_parent_inI1outR1_tail( v2_notification_t rn; pb_stream r_sa_pbs; - r_sa.isasa_np = ISAKMP_NEXT_v2KE; /* XXX */ + if (!DBGP(IMPAIR_SEND_IKEv2_KE)) { + /* normal case */ + r_sa.isasa_np = ISAKMP_NEXT_v2KE; + } else { + /* We are faking not sending a KE, we'll just call it a Notify */ + r_sa.isasa_np = ISAKMP_NEXT_v2N; + } + if (!out_struct(&r_sa, &ikev2_sa_desc, &md->rbody, &r_sa_pbs)) return STF_INTERNAL_ERROR; @@ -969,6 +985,14 @@ static stf_status ikev2_parent_inI1outR1_tail( * * */ + +/* STATE_PARENT_I1: R1 --> I2 + * <-- HDR, SAr1, KEr, Nr, [CERTREQ] + * HDR, SK {IDi, [CERT,] [CERTREQ,] + * [IDr,] AUTH, SAi2, + * TSi, TSr} --> + */ + static void ikev2_parent_inR1outI2_continue(struct pluto_crypto_req_cont *pcrc, struct pluto_crypto_req *r, err_t ugh); @@ -989,6 +1013,7 @@ stf_status ikev2parent_inR1outI2(struct msg_digest *md) v2N_COOKIE) { u_int8_t spisize; const pb_stream *dc_pbs; + DBG(DBG_CONTROLMORE, DBG_log("inR1OutI2 received a DOS v2N_COOKIE from the responder"); DBG_log("resend the I1 with a cookie payload")); @@ -1003,7 +1028,7 @@ stf_status ikev2parent_inR1outI2(struct msg_digest *md) st->st_dcookie); DBG_log("next STATE_PARENT_I1 resend I1 with the dcookie")); - md->svm = ikev2_parent_firststate(); + md->svm = &ikev2_parent_firststate_microcode; change_state(st, STATE_PARENT_I1); st->st_msgid_lastack = INVALID_MSGID; @@ -1013,23 +1038,19 @@ stf_status ikev2parent_inR1outI2(struct msg_digest *md) return ikev2_parent_outI1_common(md, st); } - /* - * If we did not get a KE payload, we cannot continue. There * should be - * a Notify telling us why. We inform the user, but continue to try this - * connection via regular retransmit intervals. - */ - if ( md->chain[ISAKMP_NEXT_v2N] && - (md->chain[ISAKMP_NEXT_v2KE] == NULL)) { - const char *from_state_name = enum_name(&state_names, - st->st_state); - const u_int16_t isan_type = - md->chain[ISAKMP_NEXT_v2N]->payload.v2n.isan_type; - libreswan_log("%s: received %s", - from_state_name, - enum_name(&ikev2_notify_names, isan_type)); - return STF_FAIL + isan_type; - } else if ( md->chain[ISAKMP_NEXT_v2N]) { - DBG(DBG_CONTROL, DBG_log("received a notify..")); + { + /* + * Check for a Notify - can this happen here? XXX + */ + const char *from_state_name = enum_name(&state_names, st->st_state); + u_int16_t isan_type = 0; /* no notify payload */ + + if (md->chain[ISAKMP_NEXT_v2N]) { + isan_type = md->chain[ISAKMP_NEXT_v2N]->payload.v2n.isan_type; + libreswan_log("%s: received %s", from_state_name, + enum_name(&ikev2_notify_names, isan_type)); + } + } /* @@ -1354,16 +1375,7 @@ stf_status ikev2_decrypt_msg(struct msg_digest *md, "cleartext"); } - { - stf_status ret; - ret = - ikev2_process_payloads(md, &md->clr_pbs, st->st_state, - np); - if (ret != STF_OK) - return ret; - } - - return STF_OK; + return ikev2_process_encrypted_payloads(md, &md->clr_pbs, np); } static stf_status ikev2_send_auth(struct connection *c, @@ -1683,6 +1695,17 @@ static stf_status ikev2_parent_inR1outI2_tail( * * */ + +/* STATE_PARENT_R1: I2 --> R2 + * <-- HDR, SK {IDi, [CERT,] [CERTREQ,] + * [IDr,] AUTH, SAi2, + * TSi, TSr} + * HDR, SK {IDr, [CERT,] AUTH, + * SAr2, TSi, TSr} --> + * + * [Parent SA established] + */ + static void ikev2_parent_inI2outR2_continue(struct pluto_crypto_req_cont *pcrc, struct pluto_crypto_req *r, err_t ugh); @@ -1796,7 +1819,7 @@ static stf_status ikev2_parent_inI2outR2_tail( struct dh_continuation *dh = (struct dh_continuation *)pcrc; struct msg_digest *md = dh->md; struct state *const st = md->st; - struct connection *c = st->st_connection; + struct connection *c = st->st_connection; unsigned char *idhash_in, *idhash_out; unsigned char *authstart; unsigned int np; @@ -1810,8 +1833,8 @@ static stf_status ikev2_parent_inI2outR2_tail( /* decrypt things. */ { - stf_status ret; - ret = ikev2_decrypt_msg(md, RESPONDER); + stf_status ret = ikev2_decrypt_msg(md, RESPONDER); + if (ret != STF_OK) return ret; } @@ -2130,6 +2153,13 @@ static stf_status ikev2_parent_inI2outR2_tail( * just aren't implemented yet. * */ + +/* STATE_PARENT_I2: R2 --> I3 + * <-- HDR, SK {IDr, [CERT,] AUTH, + * SAr2, TSi, TSr} + * [Parent SA established] + */ + stf_status ikev2parent_inR2(struct msg_digest *md) { struct state *st = md->st; @@ -2149,15 +2179,15 @@ stf_status ikev2parent_inR2(struct msg_digest *md) DBG_log("ikev2 parent inR2: calculating g^{xy} in order to decrypt I2")); /* verify that there is in fact an encrypted payload */ - if (!md->chain[ISAKMP_NEXT_v2E]) { + if (md->chain[ISAKMP_NEXT_v2E] == NULL) { libreswan_log("R2 state should receive an encrypted payload"); return STF_FATAL; } /* decrypt things. */ { - stf_status ret; - ret = ikev2_decrypt_msg(md, INITIATOR); + stf_status ret = ikev2_decrypt_msg(md, INITIATOR); + if (ret != STF_OK) return ret; } @@ -2604,6 +2634,7 @@ void send_v2_notification(struct state *p1st, u_int16_t type, send_ike_msg(p1st, __FUNCTION__); } + /* add notify payload to the rbody */ bool ship_v2N(unsigned int np, u_int8_t critical, u_int8_t protoid, chunk_t *spi, @@ -2660,6 +2691,13 @@ bool ship_v2N(unsigned int np, u_int8_t critical, * * */ + +/* RFC 5996 1.4 "The INFORMATIONAL Exchange" + * + * HDR, SK {[N,] [D,] [CP,] ...} --> + * <-- HDR, SK {[N,] [D,] [CP], ...} + */ + static void v2_delete_my_family(struct state *pst) { /* We are a parent: delete our children and @@ -2697,7 +2735,7 @@ static void v2_delete_my_family(struct state *pst) stf_status process_informational_ikev2(struct msg_digest *md) { /* verify that there is in fact an encrypted payload */ - if (!md->chain[ISAKMP_NEXT_v2E]) { + if (md->chain[ISAKMP_NEXT_v2E] == NULL) { libreswan_log( "Ignoring informational exchange outside encrypted payload (rfc5996 section 1.4)"); return STF_IGNORE; diff --git a/programs/pluto/packet.c b/programs/pluto/packet.c index 258b354..53ff533 100644 --- a/programs/pluto/packet.c +++ b/programs/pluto/packet.c @@ -1164,7 +1164,7 @@ struct_desc ikev2_e_desc = { "IKEv2 Encryption Payload", * That leaves only Identification payloads as a problem. * We make all these entries NULL */ -struct_desc *const payload_descs[ISAKMP_NEXT_ROOF] = { +static struct_desc *const payload_descs[] = { NULL, /* 0 ISAKMP_NEXT_NONE (No other payload following) */ &isakmp_sa_desc, /* 1 ISAKMP_NEXT_SA (Security Association) */ NULL, /* 2 ISAKMP_NEXT_P (Proposal) */ @@ -1214,6 +1214,11 @@ struct_desc *const payload_descs[ISAKMP_NEXT_ROOF] = { &ikev2_e_desc, /* 46 ISAKMP_NEXT_v2E */ }; +const struct_desc *payload_desc(unsigned p) +{ + return p < elemsof(payload_descs) ? payload_descs[p] : NULL; +} + void init_pbs(pb_stream *pbs, u_int8_t *start, size_t len, const char *name) { pbs->container = NULL; diff --git a/programs/pluto/plutomain.c b/programs/pluto/plutomain.c index e53b540..fa41a12 100644 --- a/programs/pluto/plutomain.c +++ b/programs/pluto/plutomain.c @@ -589,6 +589,8 @@ int main(int argc, char **argv) IMPAIR_RETRANSMITS + DBG_OFFSET }, { "impair-send-bogus-isakmp-flag", no_argument, NULL, IMPAIR_SEND_BOGUS_ISAKMP_FLAG + DBG_OFFSET }, + { "impair-send-ikev2-ke", no_argument, NULL, + IMPAIR_SEND_IKEv2_KE + DBG_OFFSET }, { 0, 0, 0, 0 } }; /* Note: we don't like the way short options get parsed @@ -1293,6 +1295,8 @@ int main(int argc, char **argv) libreswan_log("Warning: IMPAIR_RETRANSMITS enabled"); if (DBGP(IMPAIR_SEND_BOGUS_ISAKMP_FLAG)) libreswan_log("Warning: IMPAIR_SEND_BOGUS_ISAKMP_FLAG enabled"); + if (DBGP(IMPAIR_SEND_IKEv2_KE)) + libreswan_log("Warning: IMPAIR_SEND_IKEv2_KE enabled"); if (DBGP(IMPAIR_DELAY_ADNS_KEY_ANSWER)) diff --git a/programs/pluto/whack.c b/programs/pluto/whack.c index 7f887a3..9f55695 100644 --- a/programs/pluto/whack.c +++ b/programs/pluto/whack.c @@ -538,8 +538,9 @@ enum option_enums { DBGOPT_IMPAIR_MINOR_VERSION_BUMP, /* cause pluto to send IKE minor version higher then we support */ DBGOPT_IMPAIR_RETRANSMITS, /* cause pluto to never retransmit packets */ DBGOPT_IMPAIR_SEND_BOGUS_ISAKMP_FLAG, /* cause pluto to never retransmit packets */ + DBGOPT_IMPAIR_SEND_IKEv2_KE, /* cause pluto to skip emitting the KE payload */ -# define DBGOPT_LAST DBGOPT_IMPAIR_SEND_BOGUS_ISAKMP_FLAG +# define DBGOPT_LAST DBGOPT_IMPAIR_SEND_IKEv2_KE }; @@ -784,6 +785,8 @@ static const struct option long_opts[] = { OO }, { "impair-send-bogus-isakmp-flag", no_argument, NULL, DBGOPT_IMPAIR_SEND_BOGUS_ISAKMP_FLAG + OO }, + { "impair-send-ikev2-ke", no_argument, NULL, + DBGOPT_IMPAIR_SEND_IKEv2_KE + OO }, { "whackrecord", required_argument, NULL, OPT_WHACKRECORD + OO }, { "whackstoprecord", required_argument, NULL, OPT_WHACKSTOPRECORD + OO }, @@ -1807,6 +1810,7 @@ int main(int argc, char **argv) case DBGOPT_IMPAIR_MINOR_VERSION_BUMP: /* --impair-minor-version-bump */ case DBGOPT_IMPAIR_RETRANSMITS: /* --impair-retransmits */ case DBGOPT_IMPAIR_SEND_BOGUS_ISAKMP_FLAG: /* --impair-send-bogus-isakmp-flag */ + case DBGOPT_IMPAIR_SEND_IKEv2_KE: /* --impair-send-ikev2-ke */ msg.debugging |= LELEM(c - DBGOPT_RAW); continue; default: diff --git a/testing/pluto/TESTLIST b/testing/pluto/TESTLIST index a99966a..adc1304 100644 --- a/testing/pluto/TESTLIST +++ b/testing/pluto/TESTLIST @@ -481,6 +481,8 @@ umlplutotest ikev2-08-delete-notify good kvmplutotest ikev2-09-rw-rsa good kvmplutotest ikev2-11-simple-psk good kvmplutotest ikev2-12-x509-ikev1 bad +kvmplutotest ikev2-13-ah good +kvmplutotest ikev2-14-missing-ke good umlplutotest ikev2-x509-01 good umlplutotest ikev2-x509-02 good diff --git a/testing/pluto/ikev2-14-missing-ke/description.txt b/testing/pluto/ikev2-14-missing-ke/description.txt new file mode 100644 index 0000000..e43cb8e --- /dev/null +++ b/testing/pluto/ikev2-14-missing-ke/description.txt @@ -0,0 +1,4 @@ +Basic pluto with IKEv2 using PSK but west has been told to skip sending +the KE payload. This is to confirm the fix for CVE-2013-6467, which +affects libreswan up to 3.7 (and openswan up to at least 2.6.39) +This test produces a crash and core file on those older versions diff --git a/testing/pluto/ikev2-14-missing-ke/east.conf b/testing/pluto/ikev2-14-missing-ke/east.conf new file mode 100644 index 0000000..be6e7b5 --- /dev/null +++ b/testing/pluto/ikev2-14-missing-ke/east.conf @@ -0,0 +1,20 @@ +# /etc/ipsec.conf - Libreswan IPsec configuration file + +version 2.0 + +config setup + # put the logs in /tmp for the UMLs, so that we can operate + # without syslogd, which seems to break on UMLs + plutostderrlog=/tmp/pluto.log + plutodebug=all + plutorestartoncrash=false + dumpdir=/tmp + protostack=klips + nat_traversal=yes + virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!192.0.2.0/24,%v6:!2001:db8:0:2::/64 + +conn westnet-eastnet-ipv4-psk-ikev2 + also=westnet-eastnet-ipv4-psk + ikev2=insist + +include /testing/baseconfigs/all/etc/ipsec.d/ipsec.conf.common diff --git a/testing/pluto/ikev2-14-missing-ke/east.console.txt b/testing/pluto/ikev2-14-missing-ke/east.console.txt new file mode 100644 index 0000000..9a8459d --- /dev/null +++ b/testing/pluto/ikev2-14-missing-ke/east.console.txt @@ -0,0 +1,43 @@ +/testing/guestbin/swan-prep +east # + ipsec _stackmanager start +[ 00.00] NET: Registered protocol family 15 +[ 00.00] registered KLIPS /proc/sys/net +[ 00.00] ipsec_3des_init(alg_type=15 alg_id=3 name=3des): ret=0 +[ 00.00] KLIPS cryptoapi interface: alg_type=15 alg_id=12 name=cbc(aes) keyminbits=128 keymaxbits=256, found(0) +[ 00.00] KLIPS cryptoapi interface: alg_type=15 alg_id=253 name=cbc(twofish) keyminbits=128 keymaxbits=256, found(0) +[ 00.00] KLIPS cryptoapi interface: alg_type=15 alg_id=252 name=cbc(serpent) keyminbits=128 keymaxbits=256, found(0) +[ 00.00] KLIPS cryptoapi interface: alg_type=15 alg_id=6 name=cbc(cast5) keyminbits=128 keymaxbits=128, found(0) +[ 00.00] KLIPS cryptoapi interface: alg_type=15 alg_id=3 name=cbc(des3_ede) keyminbits=192 keymaxbits=192, found(0) +[ 00.00] +east # + /usr/local/libexec/ipsec/pluto --config /etc/ipsec.conf +east # + /testing/pluto/bin/wait-until-pluto-started +east # + ipsec auto --add westnet-eastnet-ipv4-psk-ikev2 +east # + echo "initdone" +initdone +east # + ipsec look +east NOW +ipsec0->eth1 mtu=16260(9999)->1500 +ROUTING TABLES +default via 192.1.2.254 dev eth1 +169.254.0.0/16 dev eth0 scope link metric 1002 +169.254.0.0/16 dev eth1 scope link metric 1003 +169.254.0.0/16 dev eth2 scope link metric 1004 +192.0.1.0/24 via 192.1.2.45 dev eth1 +192.0.2.0/24 dev eth0 proto kernel scope link src 192.0.2.254 +192.1.2.0/24 dev eth1 proto kernel scope link src 192.1.2.23 +192.9.2.0/24 dev eth2 proto kernel scope link src 192.9.2.23 +NSS_CERTIFICATES +Certificate Nickname Trust Attributes + SSL,S/MIME,JAR/XPI +east # +east # + if [ -n "`ls /tmp/core* 2>/dev/null`" ]; then echo CORE FOUND; mv /tmp/core* ./; fi +east # + if [ -f /sbin/ausearch ]; then ausearch -r -m avc -ts recent ; fi + diff --git a/testing/pluto/ikev2-14-missing-ke/east.secrets b/testing/pluto/ikev2-14-missing-ke/east.secrets new file mode 100644 index 0000000..c6b04cd --- /dev/null +++ b/testing/pluto/ikev2-14-missing-ke/east.secrets @@ -0,0 +1 @@ +@east @west : PSK "geheim" diff --git a/testing/pluto/ikev2-14-missing-ke/eastinit.sh b/testing/pluto/ikev2-14-missing-ke/eastinit.sh new file mode 100755 index 0000000..4f87806 --- /dev/null +++ b/testing/pluto/ikev2-14-missing-ke/eastinit.sh @@ -0,0 +1,6 @@ +/testing/guestbin/swan-prep +ipsec _stackmanager start +/usr/local/libexec/ipsec/pluto --config /etc/ipsec.conf +/testing/pluto/bin/wait-until-pluto-started +ipsec auto --add westnet-eastnet-ipv4-psk-ikev2 +echo "initdone" diff --git a/testing/pluto/ikev2-14-missing-ke/final.sh b/testing/pluto/ikev2-14-missing-ke/final.sh new file mode 100755 index 0000000..744c82d --- /dev/null +++ b/testing/pluto/ikev2-14-missing-ke/final.sh @@ -0,0 +1,7 @@ +ipsec look +: ==== cut ==== +ipsec auto --status +: ==== tuc ==== +if [ -n "`ls /tmp/core* 2>/dev/null`" ]; then echo CORE FOUND; mv /tmp/core* ./; fi +if [ -f /sbin/ausearch ]; then ausearch -r -m avc -ts recent ; fi +: ==== end ==== diff --git a/testing/pluto/ikev2-14-missing-ke/west.conf b/testing/pluto/ikev2-14-missing-ke/west.conf new file mode 100644 index 0000000..9e6f54a --- /dev/null +++ b/testing/pluto/ikev2-14-missing-ke/west.conf @@ -0,0 +1,21 @@ +# /etc/ipsec.conf - Libreswan IPsec configuration file + +version 2.0 + +config setup + # put the logs in /tmp for the UMLs, so that we can operate + # without syslogd, which seems to break on UMLs + plutostderrlog=/tmp/pluto.log + plutodebug=all + plutorestartoncrash=false + dumpdir=/tmp + nat_traversal=yes + virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!192.0.1.0/24,%v6:!2001:db8:0:1::/64 + protostack=klips + +conn westnet-eastnet-ipv4-psk-ikev2 + also=westnet-eastnet-ipv4-psk + ikev2=insist + +include /testing/baseconfigs/all/etc/ipsec.d/ipsec.conf.common + diff --git a/testing/pluto/ikev2-14-missing-ke/west.console.txt b/testing/pluto/ikev2-14-missing-ke/west.console.txt new file mode 100644 index 0000000..4142856 --- /dev/null +++ b/testing/pluto/ikev2-14-missing-ke/west.console.txt @@ -0,0 +1,69 @@ +/testing/guestbin/swan-prep +west # + # confirm that the network is alive +west # + ping -n -c 4 -I 192.0.1.254 192.0.2.254 +PING 192.0.2.254 (192.0.2.254) from 192.0.1.254 : 56(84) bytes of data. +64 bytes from 192.0.2.254: icmp_req=1 ttl=64 time=0.XXX ms +64 bytes from 192.0.2.254: icmp_req=2 ttl=64 time=0.XXX ms +64 bytes from 192.0.2.254: icmp_req=3 ttl=64 time=0.XXX ms +64 bytes from 192.0.2.254: icmp_req=4 ttl=64 time=0.XXX ms +--- 192.0.2.254 ping statistics --- +4 packets transmitted, 4 received, 0% packet loss, time XXXX +rtt min/avg/max/mdev = 0.XXX/0.XXX/0.XXX/0.XXX ms +west # + # make sure that clear text does not get through +west # + iptables -A INPUT -i eth1 -s 192.0.2.0/24 -j LOGDROP +west # + # confirm with a ping +west # + ping -n -c 4 -I 192.0.1.254 192.0.2.254 +PING 192.0.2.254 (192.0.2.254) from 192.0.1.254 : 56(84) bytes of data. +[ 00.00] IN=eth1 OUT= MAC=12:00:00:64:64:45:12:00:00:64:64:23:08:00 SRC=192.0.2.254 DST=192.0.1.254 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=000 PROTO=ICMP TYPE=0 CODE=0 ID=000 SEQ=1 +[ 00.00] IN=eth1 OUT= MAC=12:00:00:64:64:45:12:00:00:64:64:23:08:00 SRC=192.0.2.254 DST=192.0.1.254 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=000 PROTO=ICMP TYPE=0 CODE=0 ID=000 SEQ=2 +[ 00.00] IN=eth1 OUT= MAC=12:00:00:64:64:45:12:00:00:64:64:23:08:00 SRC=192.0.2.254 DST=192.0.1.254 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=000 PROTO=ICMP TYPE=0 CODE=0 ID=000 SEQ=3 +[ 00.00] IN=eth1 OUT= MAC=12:00:00:64:64:45:12:00:00:64:64:23:08:00 SRC=192.0.2.254 DST=192.0.1.254 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=000 PROTO=ICMP TYPE=0 CODE=0 ID=000 SEQ=4 +--- 192.0.2.254 ping statistics --- +4 packets transmitted, 0 received, 100% packet loss, time XXXX +west # + ipsec _stackmanager start +[ 00.00] NET: Registered protocol family 15 +[ 00.00] registered KLIPS /proc/sys/net +[ 00.00] ipsec_3des_init(alg_type=15 alg_id=3 name=3des): ret=0 +[ 00.00] KLIPS cryptoapi interface: alg_type=15 alg_id=12 name=cbc(aes) keyminbits=128 keymaxbits=256, found(0) +[ 00.00] KLIPS cryptoapi interface: alg_type=15 alg_id=253 name=cbc(twofish) keyminbits=128 keymaxbits=256, found(0) +[ 00.00] KLIPS cryptoapi interface: alg_type=15 alg_id=252 name=cbc(serpent) keyminbits=128 keymaxbits=256, found(0) +[ 00.00] KLIPS cryptoapi interface: alg_type=15 alg_id=6 name=cbc(cast5) keyminbits=128 keymaxbits=128, found(0) +[ 00.00] KLIPS cryptoapi interface: alg_type=15 alg_id=3 name=cbc(des3_ede) keyminbits=192 keymaxbits=192, found(0) +[ 00.00] alg: No test for cipher_null (cipher_null-generic) +[ 00.00] alg: No test for ecb(cipher_null) (ecb-cipher_null) +[ 00.00] alg: No test for digest_null (digest_null-generic) +[ 00.00] alg: No test for compress_null (compress_null-generic) +[ 00.00] KLIPS: lookup for ciphername=cipher_null: not found +[ 00.00] +west # + /usr/local/libexec/ipsec/pluto --config /etc/ipsec.conf +west # + /testing/pluto/bin/wait-until-pluto-started +west # + ipsec whack --debug-all --impair-send-ikev2-ke +west # + ipsec auto --add westnet-eastnet-ipv4-psk-ikev2 +west # + echo "initdone" +initdone +west # + ipsec auto --up westnet-eastnet-ipv4-psk-ikev2 +133 "westnet-eastnet-ipv4-psk-ikev2" #1: STATE_PARENT_I1: initiate +133 "westnet-eastnet-ipv4-psk-ikev2" #1: STATE_PARENT_I1: sent v2I1, expected v2R1 +207 "westnet-eastnet-ipv4-psk-ikev2" #1: STATE_PARENT_I1: v2N_INVALID_SYNTAX +010 "westnet-eastnet-ipv4-psk-ikev2" #1: STATE_PARENT_I1: retransmission; will wait 20s for response +207 "westnet-eastnet-ipv4-psk-ikev2" #1: STATE_PARENT_I1: v2N_INVALID_SYNTAX +010 "westnet-eastnet-ipv4-psk-ikev2" #1: STATE_PARENT_I1: retransmission; will wait 40s for response +207 "westnet-eastnet-ipv4-psk-ikev2" #1: STATE_PARENT_I1: v2N_INVALID_SYNTAX +010 "westnet-eastnet-ipv4-psk-ikev2" #1: STATE_PARENT_I1: retransmission; will wait 40s for response +207 "westnet-eastnet-ipv4-psk-ikev2" #1: STATE_PARENT_I1: v2N_INVALID_SYNTAX +010 "westnet-eastnet-ipv4-psk-ikev2" #1: STATE_PARENT_I1: retransmission; will wait 40s for response +207 "westnet-eastnet-ipv4-psk-ikev2" #1: STATE_PARENT_I1: v2N_INVALID_SYNTAX + diff --git a/testing/pluto/ikev2-14-missing-ke/west.secrets b/testing/pluto/ikev2-14-missing-ke/west.secrets new file mode 100644 index 0000000..f3dd5a5 --- /dev/null +++ b/testing/pluto/ikev2-14-missing-ke/west.secrets @@ -0,0 +1 @@ +@west @east : PSK "geheim" diff --git a/testing/pluto/ikev2-14-missing-ke/westinit.sh b/testing/pluto/ikev2-14-missing-ke/westinit.sh new file mode 100755 index 0000000..9b53d70 --- /dev/null +++ b/testing/pluto/ikev2-14-missing-ke/westinit.sh @@ -0,0 +1,13 @@ +/testing/guestbin/swan-prep +# confirm that the network is alive +ping -n -c 4 -I 192.0.1.254 192.0.2.254 +# make sure that clear text does not get through +iptables -A INPUT -i eth1 -s 192.0.2.0/24 -j LOGDROP +# confirm with a ping +ping -n -c 4 -I 192.0.1.254 192.0.2.254 +ipsec _stackmanager start +/usr/local/libexec/ipsec/pluto --config /etc/ipsec.conf +/testing/pluto/bin/wait-until-pluto-started +ipsec whack --debug-all --impair-send-ikev2-ke +ipsec auto --add westnet-eastnet-ipv4-psk-ikev2 +echo "initdone" diff --git a/testing/pluto/ikev2-14-missing-ke/westrun.sh b/testing/pluto/ikev2-14-missing-ke/westrun.sh new file mode 100755 index 0000000..e58cfd0 --- /dev/null +++ b/testing/pluto/ikev2-14-missing-ke/westrun.sh @@ -0,0 +1,3 @@ +ipsec auto --up westnet-eastnet-ipv4-psk-ikev2 +ping -n -c 4 -I 192.0.1.254 192.0.2.254 +echo done