Skip to content

Commit

Permalink
IKEv2: Add support for Intermediate Exchange
Browse files Browse the repository at this point in the history
as per draft-ietf-ipsecme-ikev2-intermediate-05

This is configured using intermediate=yes

Signed-off-by: Sahana Prasad <sahana@redhat.com>
Signed-off-by: Paul Wouters <pwouters@redhat.com>
  • Loading branch information
kzvkva authored and letoams committed Sep 11, 2020
1 parent 4ec6444 commit 6b3b669
Show file tree
Hide file tree
Showing 22 changed files with 611 additions and 105 deletions.
15 changes: 14 additions & 1 deletion include/ietf_constants.h
Expand Up @@ -12,6 +12,7 @@
* Copyright (C) 2017 Sahana Prasad <sahana.prasad07@gmail.com>
* Copyright (C) 2017 Vukasin Karadzic <vukasin.karadzic@gmail.com>
* Copyright (C) 2017 Mayank Totale <mtotale@gmail.com>
* Copyright (C) 2020 Yulia Kuzovkova <ukuzovkova@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
Expand Down Expand Up @@ -796,7 +797,9 @@ enum isakmp_xchg_types {
ISAKMP_v2_GSA_AUTH = 39, /* draft-yeung-g-ikev2 */
ISAKMP_v2_GSA_REGISTRATION = 40, /* draft-yeung-g-ikev2 */
ISAKMP_v2_GSA_REKEY = 41, /* draft-yeung-g-ikev2 */
/* 42 - 239 Unassigned */
ISAKMP_v2_UNASSIGNED_42 = 42, /* avoid hole in enum */
ISAKMP_v2_IKE_INTERMEDIATE = 43, /* draft-ietf-ipsecme-ikev2-intermediate */
/* 42, 44 - 239 Unassigned */
/* 240 - 255 Private Use */

/* libreswan private use */
Expand All @@ -815,6 +818,15 @@ enum isakmp_xchg_types {
#define ISAKMP_FLAGS_RESERVED_BIT7 (1 << 7) /* RESERVED */
extern const char *const isakmp_flag_names[];

/* IKEv2 header field sizes and offsets from the start of the header */
#define ADJ_LENGTH_SIZE 4
#define ADJ_LENGTH_OFFSET 24
#define EXCH_TYPE_OFFSET 18

/* SK payload header field sizes */
#define SK_HEADER_SIZE 4
#define ADJ_PAYLOAD_LENGTH_SIZE 2

/* Situation definition for IPsec DOI */
extern const char *const sit_bit_names[];

Expand Down Expand Up @@ -1573,6 +1585,7 @@ typedef enum {
v2N_USE_PPK = 16435, /* draft-ietf-ipsecme-qr-ikev2 */
v2N_PPK_IDENTITY = 16436, /* draft-ietf-ipsecme-qr-ikev2 */
v2N_NO_PPK_AUTH = 16437, /* draft-ietf-ipsecme-qr-ikev2 */
v2N_INTERMEDIATE_EXCHANGE_SUPPORTED = 16438, /* draft-ietf-ipsecme-ikev2-intermediate-04 */

v2N_STATUS_PSTATS_ROOF, /* used to cap status statistics array */

Expand Down
3 changes: 2 additions & 1 deletion include/ike_alg_prf_ikev2_ops.h
@@ -1,6 +1,7 @@
/* IKEv1 PRF specific operations, for libreswan
*
* Copyright (C) 2019 Andrew Cagney <cagney@gnu.org>
* Copyright (C) 2020 Yulia Kuzovkova <ukuzovkova@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
Expand Down Expand Up @@ -61,7 +62,7 @@ struct prf_ikev2_ops {
struct crypt_mac (*psk_auth)(const struct prf_desc *prf_desc, chunk_t pss,
chunk_t first_packet, chunk_t nonce,
const struct crypt_mac *id_hash,
struct logger *logger);
struct logger *logger, bool use_intermediate, chunk_t intermediate_packet);
};

extern const struct prf_ikev2_ops ike_alg_prf_ikev2_mac_ops;
Expand Down
2 changes: 2 additions & 0 deletions include/ipsecconf/keywords.h
Expand Up @@ -12,6 +12,7 @@
* Copyright (C) 2013-2016 Antony Antony <antony@phenome.org>
* Copyright (C) 2016, Andrew Cagney <cagney@gnu.org>
* Copyright (C) 2017 Mayank Totale <mtotale@gmail.com>
* Copyright (C) 2020, Yulia Kuzovkova <ukuzovkova@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
Expand Down Expand Up @@ -240,6 +241,7 @@ enum keyword_numeric_conn_field {
KNCF_ENCAPS,
KNCF_IKEv2,
KNCF_PPK,
KNCF_INTERMEDIATE, /* enable support for Intermediate Exchange */
KNCF_ESN,
KNCF_DECAP_DSCP,
KNCF_NOPMTUDISC,
Expand Down
3 changes: 3 additions & 0 deletions include/pluto_constants.h
Expand Up @@ -10,6 +10,7 @@
* Copyright (C) 2017-2018 Sahana Prasad <sahana.prasad07@gmail.com>
* Copyright (C) 2017 Vukasin Karadzic <vukasin.karadzic@gmail.com>
* Copyright (C) 2019-2019 Andrew Cagney <cagney@gnu.org>
* Copyright (C) 2020 Yulia Kuzovkova <ukuzovkova@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
Expand Down Expand Up @@ -913,6 +914,7 @@ enum sa_policy_bits {
POLICY_PPK_INSIST_IX,
POLICY_ESN_NO_IX, /* send/accept ESNno */
POLICY_ESN_YES_IX, /* send/accept ESNyes */
POLICY_INTERMEDIATE_IX, /* allow Intermediate Exchange */
POLICY_RSASIG_v1_5_IX,
#define POLICY_IX_LAST POLICY_RSASIG_v1_5_IX
};
Expand Down Expand Up @@ -964,6 +966,7 @@ enum sa_policy_bits {
#define POLICY_PPK_INSIST LELEM(POLICY_PPK_INSIST_IX)
#define POLICY_ESN_NO LELEM(POLICY_ESN_NO_IX) /* accept or request ESNno */
#define POLICY_ESN_YES LELEM(POLICY_ESN_YES_IX) /* accept or request ESNyes */
#define POLICY_INTERMEDIATE LELEM(POLICY_INTERMEDIATE_IX) /* allow Intermediate Exchange */
#define POLICY_RSASIG_v1_5 LELEM(POLICY_RSASIG_v1_5_IX)

#define NEGOTIATE_AUTH_HASH_SHA1 LELEM(IKEv2_HASH_ALGORITHM_SHA1) /* rfc7427 does responder support SHA1? */
Expand Down
2 changes: 2 additions & 0 deletions lib/libipsecconf/confread.c
Expand Up @@ -15,6 +15,7 @@
* Copyright (C) 2016 Andrew Cagney <cagney@gnu.org>
* Copyright (C) 2017-2018 Vukasin Karadzic <vukasin.karadzic@gmail.com>
* Copyright (C) 2017 Mayank Totale <mtotale@gmail.com>
* Copyright (C) 2020 Yulia Kuzovkova <ukuzovkova@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
Expand Down Expand Up @@ -1245,6 +1246,7 @@ static bool load_conn(struct starter_conn *conn,
KW_POLICY_FLAG(KNCF_MSDH_DOWNGRADE, POLICY_MSDH_DOWNGRADE);
KW_POLICY_FLAG(KNCF_DNS_MATCH_ID, POLICY_DNS_MATCH_ID);
KW_POLICY_FLAG(KNCF_SHA2_TRUNCBUG, POLICY_SHA2_TRUNCBUG);
KW_POLICY_FLAG(KNCF_INTERMEDIATE, POLICY_INTERMEDIATE);

if (conn->options_set[KNCF_SAN_ON_CERT]) {
if (!conn->options[KNCF_SAN_ON_CERT])
Expand Down
2 changes: 2 additions & 0 deletions lib/libipsecconf/keywords.c
Expand Up @@ -9,6 +9,7 @@
* Copyright (C) 2013-2016 Antony Antony <antony@phenome.org>
* Copyright (C) 2016-2019 Andrew Cagney <cagney@gnu.org>
* Copyright (C) 2017 Mayank Totale <mtotale@gmail.com>
* Copyright (C) 2020 Yulia Kuzovkova <ukuzovkova@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
Expand Down Expand Up @@ -514,6 +515,7 @@ const struct keyword_def ipsec_conf_keywords[] = {
{ "keyexchange", kv_conn, kt_enum, KNCF_KEYEXCHANGE, &kw_keyexchange_list, NULL, },
{ "ikev2", kv_conn | kv_processed, kt_enum, KNCF_IKEv2, &kw_fourvalued_list, NULL, },
{ "ppk", kv_conn | kv_processed, kt_enum, KNCF_PPK, &kw_fourvalued_list, NULL, },
{ "intermediate", kv_conn | kv_processed, kt_bool, KNCF_INTERMEDIATE, NULL, NULL, },
{ "esn", kv_conn | kv_processed, kt_enum, KNCF_ESN, &kw_esn_list, NULL, },
{ "decap-dscp", kv_conn | kv_processed, kt_bool, KNCF_DECAP_DSCP, NULL, NULL, },
{ "nopmtudisc", kv_conn | kv_processed, kt_bool, KNCF_NOPMTUDISC, NULL, NULL, },
Expand Down
10 changes: 6 additions & 4 deletions lib/libswan/constants.c
Expand Up @@ -6,6 +6,7 @@
* Copyright (C) 2016-2017 Andrew Cagney
* Copyright (C) 2017 Vukasin Karadzic <vukasin.karadzic@gmail.com>
* Copyright (C) 2019 Andrew Cagney <cagney@gnu.org>
* Copyright (C) 2020 Yulia Kuzovkova <ukuzovkova@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
Expand Down Expand Up @@ -435,11 +436,11 @@ static const char *const exchange_name_ikev2[] = {
"ISAKMP_v2_CREATE_CHILD_SA",
"ISAKMP_v2_INFORMATIONAL",
"ISAKMP_v2_IKE_SESSION_RESUME", /* RFC 5753 */
#if 0 /* we don't recognize these yet */
"ISAKMP_v2_GSA_AUTH", /* draft-yeung-g-ikev2 */
"ISAKMP_v2_GSA_REGISTRATION", /* draft-yeung-g-ikev2 */
"ISAKMP_v2_GSA_REKEY", /* draft-yeung-g-ikev2 */
#endif
"ISAKMP_v2_UNASSIGNED_42", /* avoid hole in enum */
"ISAKMP_v2_IKE_INTERMEDIATE",
};

static const char *const exchange_name_private_use[] = {
Expand Down Expand Up @@ -473,7 +474,7 @@ enum_names ikev1_exchange_names = {

enum_names ikev2_exchange_names = {
ISAKMP_v2_IKE_SA_INIT,
ISAKMP_v2_IKE_SESSION_RESUME,
ISAKMP_v2_IKE_INTERMEDIATE,
ARRAY_REF(exchange_name_ikev2),
"ISAKMP_v2_", /* prefix */
&exchange_names_private_use
Expand Down Expand Up @@ -1761,11 +1762,12 @@ static const char *const ikev2_notify_name_16384[] = {
"v2N_USE_PPK", /* 16435 */
"v2N_PPK_IDENTITY",
"v2N_NO_PPK_AUTH",
"v2N_INTERMEDIATE_EXCHANGE_SUPPORTED" /* 16438*/,
};

static enum_names ikev2_notify_names_16384 = {
v2N_INITIAL_CONTACT,
v2N_NO_PPK_AUTH,
v2N_INTERMEDIATE_EXCHANGE_SUPPORTED,
ARRAY_REF(ikev2_notify_name_16384),
"v2N_", /* prefix */
&ikev2_notify_names_private
Expand Down
6 changes: 5 additions & 1 deletion lib/libswan/ike_alg_prf_ikev2_mac_ops.c
Expand Up @@ -213,7 +213,8 @@ static PK11SymKey *child_sa_keymat(const struct prf_desc *prf_desc,
static struct crypt_mac psk_auth(const struct prf_desc *prf_desc, chunk_t pss,
chunk_t first_packet, chunk_t nonce,
const struct crypt_mac *id_hash,
struct logger *logger)
struct logger *logger,
bool use_intermediate, chunk_t intermediate_packet)
{
/* calculate inner prf */
PK11SymKey *prf_psk;
Expand Down Expand Up @@ -263,6 +264,9 @@ static struct crypt_mac psk_auth(const struct prf_desc *prf_desc, chunk_t pss,
crypt_prf_update_hunk(prf, "first-packet", first_packet);
crypt_prf_update_hunk(prf, "nonce", nonce);
crypt_prf_update_hunk(prf, "hash", *id_hash);
if (use_intermediate) {
crypt_prf_update_hunk(prf,"IntAuth", intermediate_packet);
}
signed_octets = crypt_prf_final_mac(&prf, NULL);
}
release_symkey(__func__, "prf-psk", &prf_psk);
Expand Down
2 changes: 2 additions & 0 deletions programs/pluto/demux.h
Expand Up @@ -6,6 +6,7 @@
* Copyright (C) 2013 Wolfgang Nothdurft <wolfgang@linogate.de>
* Copyright (C) 2018-2019 Andrew Cagney <cagney@gnu.org>
* Copyright (C) 2017 Mayank Totale <mtotale@gmail.com>
* Copyright (C) 2020 Yulia Kuzovkova <ukuzovkova@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
Expand Down Expand Up @@ -110,6 +111,7 @@ enum v2_pbs {
PBS_v2N_INVALID_KE_PAYLOAD,
PBS_v2N_INVALID_MAJOR_VERSION,
PBS_v2N_TS_UNACCEPTABLE,
PBS_v2N_INTERMEDIATE_EXCHANGE_SUPPORTED,

PBS_v2_ROOF,
};
Expand Down
46 changes: 45 additions & 1 deletion programs/pluto/ikev2.c
Expand Up @@ -14,6 +14,7 @@
* Copyright (C) 2015-2019 Andrew Cagney
* Copyright (C) 2016-2018 Antony Antony <appu@phenome.org>
* Copyright (C) 2017 Sahana Prasad <sahana.prasad07@gmail.com>
* Copyright (C) 2020 Yulia Kuzovkova <ukuzovkova@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
Expand Down Expand Up @@ -285,7 +286,7 @@ static /*const*/ struct state_v2_microcode v2_state_microcode_table[] = {
* [IDr,] AUTH, SAi2,
* TSi, TSr} -->
*/
{ .story = "Initiator: process IKE_SA_INIT reply, initiate IKE_AUTH",
{ .story = "Initiator: process IKE_SA_INIT reply, initiate IKE_AUTH or IKE_INTERMEDIATE",
.state = STATE_PARENT_I1,
.next_state = STATE_PARENT_I2,
.send = MESSAGE_REQUEST,
Expand All @@ -296,6 +297,18 @@ static /*const*/ struct state_v2_microcode v2_state_microcode_table[] = {
.recv_type = ISAKMP_v2_IKE_SA_INIT,
.timeout_event = EVENT_RETRANSMIT, },

{ .story = "Initiator: process IKE_INTERMEDIATE reply, initiate IKE_AUTH or IKE_INTERMEDIATE",
.state = STATE_PARENT_I2,
.next_state = STATE_PARENT_I2,
.flags = MESSAGE_RESPONSE,
.send = MESSAGE_REQUEST,
.req_clear_payloads = P(SK),
.opt_clear_payloads = LEMPTY,
.processor = ikev2_parent_inR1outI2,
.recv_role = MESSAGE_RESPONSE,
.recv_type = ISAKMP_v2_IKE_INTERMEDIATE,
.timeout_event = EVENT_RETRANSMIT, },

/* STATE_PARENT_I2: R2 -->
* <-- HDR, SK {IDr, [CERT,] AUTH,
* SAr2, TSi, TSr}
Expand Down Expand Up @@ -384,6 +397,32 @@ static /*const*/ struct state_v2_microcode v2_state_microcode_table[] = {
.recv_role = MESSAGE_REQUEST,
.recv_type = ISAKMP_v2_IKE_AUTH,
.timeout_event = EVENT_SA_REPLACE, },

{ .story = "Responder: process IKE_INTERMEDIATE request (no SKEYSEED)",
.state = STATE_PARENT_R1,
.next_state = STATE_PARENT_R1,
.flags = MESSAGE_REQUEST | SMF2_NO_SKEYSEED,
.send = MESSAGE_RESPONSE,
.req_clear_payloads = P(SK),
.req_enc_payloads = LEMPTY,
.opt_enc_payloads = LEMPTY,
.processor = ikev2_ike_sa_process_intermediate_request_no_skeyid,
.recv_role = MESSAGE_REQUEST,
.recv_type = ISAKMP_v2_IKE_INTERMEDIATE,
.timeout_event = EVENT_SA_REPLACE, },

{ .story = "Responder: process IKE_INTERMEDIATE request (with SKEYSEED)",
.state = STATE_PARENT_R1,
.next_state = STATE_PARENT_R1,
.flags = MESSAGE_REQUEST,
.send = MESSAGE_RESPONSE,
.req_clear_payloads = P(SK),
.req_enc_payloads = LEMPTY,
.opt_enc_payloads = LEMPTY,
.processor = ikev2_ike_sa_process_auth_request,
.recv_role = MESSAGE_REQUEST,
.recv_type = ISAKMP_v2_IKE_INTERMEDIATE,
.timeout_event = EVENT_SA_REPLACE, },
/*
* XXX: Danger! This state transition mashes the IKE SA's
* initial state and the CHILD SA's final state. There should
Expand Down Expand Up @@ -3081,6 +3120,11 @@ static void success_v2_state_transition(struct state *st, struct msg_digest *md,
log_st = st;
/* log our success and trigger detach */
w = RC_SUCCESS;
} else if (transition->state == STATE_PARENT_I1 &&
transition->next_state == STATE_PARENT_I2) {
log_details = lswlog_ike_sa_established;
log_st = &ike->sa;
w = RC_NEW_V2_STATE + st->st_state->kind;
} else if (st->st_state->kind == STATE_PARENT_I2) {
/*
* Hack around md->st being forced to the CHILD_SA
Expand Down
2 changes: 2 additions & 0 deletions programs/pluto/ikev2.h
Expand Up @@ -6,6 +6,7 @@
* Copyright (C) 2018 Paul Wouters <pwouters@redhat.com>
* Copyright (C) 2017-2019 Andrew Cagney <cagney@gnu.org>
* Copyright (C) 2018 Sahana Prasad <sahana.prasad07@gmail.com>
* Copyright (C) 2020 Yulia Kuzovkova <ukuzovkova@gmail.com>
*/

#ifndef IKEV2_H
Expand Down Expand Up @@ -57,6 +58,7 @@ extern ikev2_state_transition_fn ikev2_child_inIoutR;
extern ikev2_state_transition_fn ikev2_parent_inI1outR1;
extern ikev2_state_transition_fn ikev2_auth_initiator_process_failure_notification;
extern ikev2_state_transition_fn ikev2_auth_initiator_process_unknown_notification;
extern ikev2_state_transition_fn ikev2_ike_sa_process_intermediate_request_no_skeyid;
extern ikev2_state_transition_fn ikev2_ike_sa_process_auth_request_no_skeyid;
extern ikev2_state_transition_fn ikev2_ike_sa_process_auth_request;
extern ikev2_state_transition_fn ikev2_parent_inR1outI2;
Expand Down
18 changes: 18 additions & 0 deletions programs/pluto/ikev2_auth.c
Expand Up @@ -8,6 +8,7 @@
* Copyright (C) 2013-2019 D. Hugh Redelmeier <hugh@mimosa.com>
* Copyright (C) 2018 Sahana Prasad <sahana.prasad07@gmail.com>
* Copyright (C) 2019 Andrew Cagney <cagney@gnu.org>
* Copyright (C) 2020 Yulia Kuzovkova <ukuzovkova@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
Expand Down Expand Up @@ -48,16 +49,27 @@ struct crypt_mac v2_calculate_sighash(const struct ike_sa *ike,
{
enum sa_role role;
chunk_t firstpacket;
chunk_t intermediate_auth;
switch (from_the_perspective_of) {
case LOCAL_PERSPECTIVE:
firstpacket = ike->sa.st_firstpacket_me;
role = ike->sa.st_sa_role;
if (ike->sa.st_intermediate_used) {
intermediate_auth = clone_hunk(ike->sa.st_intermediate_packet_me, "IntAuth_*_I");
intermediate_auth = clone_chunk_chunk(intermediate_auth, ike->sa.st_intermediate_packet_peer,
"IntAuth_*_I_A | IntAuth_*_R");
}
break;
case REMOTE_PERSPECTIVE:
firstpacket = ike->sa.st_firstpacket_peer;
role = (ike->sa.st_sa_role == SA_INITIATOR ? SA_RESPONDER :
ike->sa.st_sa_role == SA_RESPONDER ? SA_INITIATOR :
0);
if (ike->sa.st_intermediate_used) {
intermediate_auth = clone_hunk(ike->sa.st_intermediate_packet_peer, "IntAuth_*_I");
intermediate_auth = clone_chunk_chunk(intermediate_auth, ike->sa.st_intermediate_packet_me,
"IntAuth_*_I_A | IntAuth_*_R");
}
break;
default: bad_case(from_the_perspective_of);
}
Expand All @@ -83,6 +95,9 @@ struct crypt_mac v2_calculate_sighash(const struct ike_sa *ike,
DBG_dump_hunk("inputs to hash1 (first packet)", firstpacket);
DBG_dump_hunk(nonce_name, *nonce);
DBG_dump_hunk("idhash", *idhash);
if (ike->sa.st_intermediate_used) {
DBG_dump_hunk("IntAuth", intermediate_auth);
}
}

struct crypt_hash *ctx = crypt_hash_init("sighash", hasher,
Expand All @@ -92,6 +107,9 @@ struct crypt_mac v2_calculate_sighash(const struct ike_sa *ike,
/* we took the PRF(SK_d,ID[ir]'), so length is prf hash length */
passert(idhash->len == ike->sa.st_oakley.ta_prf->prf_output_size);
crypt_hash_digest_hunk(ctx, "IDHASH", *idhash);
if (ike->sa.st_intermediate_used) {
crypt_hash_digest_hunk(ctx, "IntAuth", intermediate_auth);
}
return crypt_hash_final_mac(&ctx);
}

Expand Down
2 changes: 2 additions & 0 deletions programs/pluto/ikev2_child.c
Expand Up @@ -8,6 +8,7 @@
* Copyright (C) 2013-2019 D. Hugh Redelmeier <hugh@mimosa.com>
* Copyright (C) 2014-2019 Andrew Cagney <cagney@gnu.org>
* Copyright (C) 2017 Antony Antony <antony@phenome.org>
* Copyright (C) 2020 Yulia Kuzovkova <ukuzovkova@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
Expand Down Expand Up @@ -153,6 +154,7 @@ stf_status ikev2_child_sa_respond(struct ike_sa *ike,
case v2N_IKEV2_FRAGMENTATION_SUPPORTED:
case v2N_COOKIE:
case v2N_USE_PPK:
case v2N_INTERMEDIATE_EXCHANGE_SUPPORTED:
dbg("received %s which is not valid for current exchange",
enum_name(&ikev2_notify_names, ntfy->payload.v2n.isan_type));
break;
Expand Down

0 comments on commit 6b3b669

Please sign in to comment.