[openswan] Ikev2 changes from rhel6 to fedora
avesh
avesh at fedoraproject.org
Tue Aug 7 20:23:00 UTC 2012
commit 5f429c95abcbc6eee1e06dae09a71196544b8303
Author: Avesh Agarwal <avagarwa at redhat.com>
Date: Tue Aug 7 16:22:28 2012 -0400
Ikev2 changes from rhel6 to fedora
- Sha256 changes from rhel6 to fedora
- Fixed 384/512 changes from rhel6 to fedora
- Ported cisco-openswan interop changes in aggresive/main mode
- Labeld-ipsec fixes
- aes-gcm fixes in ikev1 mode
- updown netkey script changes related to updating/removing
interface ip address and routes
- Fixes related to rhbz 609343
- Fixes related to rhbz 831676
openswan-2.6-relpath.patch | 24 +-
openswan-cisco-aggr-mode.patch | 169 ++
openswan-cisco-issues.patch | 134 -
openswan-ikev1-aes-gcm-esp-fixes.patch | 163 +
openswan-ikev1-ikev2-sha256.patch | 165 ++
openswan-ikev1-ikev2-sha384-512.patch | 633 ++++
openswan-ikev2.patch | 3116 ++++++++++++++++++++
openswan-ipsec-help-524146-509318.patch | 13 +-
openswan-labeled-ipsec.patch | 115 +
openswan-updown-netkey.patch | 83 +
openswan.spec | 36 +-
...g-password-from-a-file-when-creating-keys.patch | 19 +
rhbz-609343.patch | 32 +
rhbz-831676.patch | 107 +
rhbz-841325.patch | 56 +
15 files changed, 4718 insertions(+), 147 deletions(-)
---
diff --git a/openswan-2.6-relpath.patch b/openswan-2.6-relpath.patch
index de4dfa8..caa0913 100644
--- a/openswan-2.6-relpath.patch
+++ b/openswan-2.6-relpath.patch
@@ -1,7 +1,14 @@
-diff -urNp openswan-2.6.38-patched/Makefile.inc openswan-2.6.38-current/Makefile.inc
---- openswan-2.6.38-patched/Makefile.inc 2012-05-14 15:17:33.573272378 -0400
-+++ openswan-2.6.38-current/Makefile.inc 2012-05-14 15:18:40.817270688 -0400
-@@ -129,6 +129,8 @@ FINALRCDIR?=$(shell for d in $(INC_RCDIR
+From 4aa18c8394b9d315332a3a0ab8d62fb60a8102db Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Thu, 29 Sep 2011 15:57:13 -0400
+Subject: Openswan 2.6 relpath changes
+
+
+diff --git a/Makefile.inc b/Makefile.inc
+index c827328..15e4724 100644
+--- a/Makefile.inc
++++ b/Makefile.inc
+@@ -129,6 +129,8 @@ FINALRCDIR?=$(shell for d in $(INC_RCDIRS) ; \
do if test -d $(DESTDIR)/$$d ; \
then echo $$d ; exit 0 ; \
fi ; done ; echo $(INC_RCDEFAULT) )
@@ -10,10 +17,11 @@ diff -urNp openswan-2.6.38-patched/Makefile.inc openswan-2.6.38-current/Makefile
RCDIR?=$(DESTDIR)$(FINALRCDIR)
-diff -urNp openswan-2.6.38-patched/programs/setup/Makefile openswan-2.6.38-current/programs/setup/Makefile
---- openswan-2.6.38-patched/programs/setup/Makefile 2012-05-14 15:17:33.568272379 -0400
-+++ openswan-2.6.38-current/programs/setup/Makefile 2012-05-14 15:18:40.817270688 -0400
-@@ -35,7 +35,7 @@ doinstall:: $(PROGRAM) $(CONFFILES) $(EX
+diff --git a/programs/setup/Makefile b/programs/setup/Makefile
+index 7ac3dbe..872cea3 100644
+--- a/programs/setup/Makefile
++++ b/programs/setup/Makefile
+@@ -35,7 +35,7 @@ doinstall:: $(PROGRAM) $(CONFFILES) $(EXTRA8MAN) $(EXTRA5MAN) $(EXTRA5PROC) $(LI
@mkdir -p $(RCDIR) $(BINDIR)
# install and link everything
@$(INSTALL) $(INSTBINFLAGS) setup $(RCDIR)/ipsec
diff --git a/openswan-cisco-aggr-mode.patch b/openswan-cisco-aggr-mode.patch
new file mode 100644
index 0000000..36c9f2e
--- /dev/null
+++ b/openswan-cisco-aggr-mode.patch
@@ -0,0 +1,169 @@
+From 724b4adf9bcaa144cff6bd7cbc6359d005bff5df Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Tue, 7 Aug 2012 11:31:21 -0400
+Subject: Fixes to solve interop issues between cisco ASA and openswan in
+ aggressive mode.
+
+
+diff --git a/programs/pluto/connections.c b/programs/pluto/connections.c
+index 6e5dbd9..eb2b492 100644
+--- a/programs/pluto/connections.c
++++ b/programs/pluto/connections.c
+@@ -222,7 +222,7 @@ delete_end(struct connection *c UNUSED, struct spd_route *sr UNUSED, struct end
+ pfreeany(e->host_addr_name);
+ }
+
+-static void
++void
+ delete_sr(struct connection *c, struct spd_route *sr)
+ {
+ delete_end(c, sr, &sr->this);
+diff --git a/programs/pluto/connections.h b/programs/pluto/connections.h
+index f385e24..36f8517 100644
+--- a/programs/pluto/connections.h
++++ b/programs/pluto/connections.h
+@@ -321,6 +321,7 @@ extern void release_connection(struct connection *c, bool relations);
+ extern void delete_connection(struct connection *c, bool relations);
+ extern void delete_connections_by_name(const char *name, bool strict);
+ extern void delete_every_connection(void);
++extern void delete_sr(struct connection *c, struct spd_route *sr);
+ extern char *add_group_instance(struct connection *group, const ip_subnet *target);
+ extern void remove_group_instance(const struct connection *group, const char *name);
+ extern void release_dead_interfaces(void);
+diff --git a/programs/pluto/ikev1_aggr.c b/programs/pluto/ikev1_aggr.c
+index 8569e2c..3f722af 100644
+--- a/programs/pluto/ikev1_aggr.c
++++ b/programs/pluto/ikev1_aggr.c
+@@ -813,18 +813,6 @@ aggr_inR1_outI2_tail(struct msg_digest *md
+ }
+ #endif
+
+- if(c->newest_isakmp_sa != SOS_NOBODY && st->st_connection->spd.this.xauth_client && st->st_connection->remotepeertype == CISCO) {
+- DBG(DBG_CONTROL, DBG_log("This seems to be rekey, and XAUTH is not supposed to be done again"));
+- st->hidden_variables.st_xauth_client_done = TRUE;
+- st->st_oakley.xauth = 0;
+-
+- if(st->st_connection->spd.this.modecfg_client) {
+- DBG(DBG_CONTROL, DBG_log("This seems to be rekey, and MODECFG is not supposed to be done again"));
+- st->hidden_variables.st_modecfg_vars_set = TRUE;
+- st->hidden_variables.st_modecfg_started = TRUE;
+- }
+- }
+-
+ c->newest_isakmp_sa = st->st_serialno;
+
+ /* save last IV from phase 1 so it can be restored later so anything
+@@ -931,18 +919,6 @@ aggr_inI2_tail(struct msg_digest *md
+ }
+ #endif
+
+- if(c->newest_isakmp_sa != SOS_NOBODY && st->st_connection->spd.this.xauth_client && st->st_connection->remotepeertype == CISCO) {
+- DBG(DBG_CONTROL, DBG_log("This seems to be rekey, and XAUTH is not supposed to be done again"));
+- st->hidden_variables.st_xauth_client_done = TRUE;
+- st->st_oakley.xauth = 0;
+-
+- if(st->st_connection->spd.this.modecfg_client) {
+- DBG(DBG_CONTROL, DBG_log("This seems to be rekey, and MODECFG is not supposed to be done again"));
+- st->hidden_variables.st_modecfg_vars_set = TRUE;
+- st->hidden_variables.st_modecfg_started = TRUE;
+- }
+- }
+-
+ c->newest_isakmp_sa = st->st_serialno;
+
+ update_iv(st); /* Finalize our Phase 1 IV */
+diff --git a/programs/pluto/xauth.c b/programs/pluto/xauth.c
+index 36a9f07..5d437ca 100644
+--- a/programs/pluto/xauth.c
++++ b/programs/pluto/xauth.c
+@@ -1785,7 +1785,9 @@ modecfg_inR1(struct msg_digest *md)
+ , caddr);
+
+ if(addrbytesptr(&c->spd.this.host_srcip, NULL) == 0
+- || isanyaddr(&c->spd.this.host_srcip)) {
++ || isanyaddr(&c->spd.this.host_srcip)
++ || c->remotepeertype == CISCO ) {
++ /*with remotepeertype == CISCO, overwrite the previous address with the new received address*/
+ openswan_log("setting ip source address to %s"
+ , caddr);
+ c->spd.this.host_srcip = a;
+@@ -1796,6 +1798,7 @@ modecfg_inR1(struct msg_digest *md)
+
+ case INTERNAL_IP4_NETMASK:
+ {
++ //struct connection *c = st->st_connection;
+ ip_address a;
+ char caddr[SUBNETTOT_BUF];
+
+@@ -1806,6 +1809,8 @@ modecfg_inR1(struct msg_digest *md)
+
+ addrtot(&a, 0, caddr, sizeof(caddr));
+ openswan_log("Received IP4 NETMASK %s", caddr);
++ //c->spd.this.client.maskbits = masktocount(&a);
++ //openswan_log("setting received mask of local client to %d", c->spd.this.client.maskbits);
+ }
+ resp |= LELEM(attr.isaat_af_type);
+ break;
+@@ -1835,7 +1840,11 @@ modecfg_inR1(struct msg_digest *md)
+ {
+ /* concatenate new IP address string on end of
+ * existing string, separated by ' '.
++ * concatenate only if the received DNS is not
++ * already present in the current string.
+ */
++
++ if( !strstr(c->cisco_dns_info, caddr) ) {
+ size_t sz_old = strlen(old);
+ size_t sz_added = strlen(caddr) + 1;
+ char *new = alloc_bytes(sz_old + 1 + sz_added, "cisco_dns_info+");
+@@ -1845,6 +1854,7 @@ modecfg_inR1(struct msg_digest *md)
+ memcpy(new + sz_old + 1, caddr, sz_added);
+ c->cisco_dns_info = new;
+ pfree(old);
++ }
+ }
+ }
+
+@@ -1860,18 +1870,22 @@ modecfg_inR1(struct msg_digest *md)
+ break;
+
+ case CISCO_BANNER:
++ /*if received again, free the previous and create the new one*/
++ pfreeany(st->st_connection->cisco_banner);
+ st->st_connection->cisco_banner = cisco_stringify(&strattr,"Cisco Banner");
+ resp |= LELEM(attr.isaat_af_type);
+ break;
+
+ case CISCO_DEF_DOMAIN:
++ /*if received again, free the previous one and create the new one*/
++ pfreeany(st->st_connection->cisco_domain_info);
+ st->st_connection->cisco_domain_info = cisco_stringify(&strattr,"Cisco Domain");
+ resp |= LELEM(attr.isaat_af_type);
+ break;
+
+ case CISCO_SPLIT_INC:
+ {
+- struct spd_route *tmp_spd;
++ struct spd_route *tmp_spd, *tmp_spd1;
+ ip_address a;
+ char caddr[SUBNETTOT_BUF];
+ size_t len = pbs_left(&strattr);
+@@ -1884,6 +1898,18 @@ modecfg_inR1(struct msg_digest *md)
+ tmp_spd2->that.has_client_wildcard = FALSE;
+ }
+
++ /* receiving remote subnets information again
++ * free the previous ones before proceeding.
++ */
++ tmp_spd = tmp_spd2->next;
++ tmp_spd2->next = NULL;
++ while(tmp_spd ) {
++ delete_sr(c, tmp_spd);
++ tmp_spd1 = tmp_spd->next;
++ pfree(tmp_spd);
++ tmp_spd = tmp_spd1;
++ }
++
+ while (len > 0) {
+ u_int32_t *ap;
+ tmp_spd = clone_thing(c->spd, "remote subnets policies");
diff --git a/openswan-ikev1-aes-gcm-esp-fixes.patch b/openswan-ikev1-aes-gcm-esp-fixes.patch
new file mode 100644
index 0000000..87c34d8
--- /dev/null
+++ b/openswan-ikev1-aes-gcm-esp-fixes.patch
@@ -0,0 +1,163 @@
+From d3ca106d9db9e59b03755c66fe71d618357e16bc Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Fri, 3 Aug 2012 14:49:06 -0400
+Subject: ikev1 aes-gcm esp fixes
+
+
+diff --git a/lib/libopenswan/alg_info.c b/lib/libopenswan/alg_info.c
+index 796fbfb..b5af2ce 100644
+--- a/lib/libopenswan/alg_info.c
++++ b/lib/libopenswan/alg_info.c
+@@ -621,6 +621,26 @@ parser_alg_info_add(struct parser_context *p_ctx
+ p_ctx->err="enc_alg not found";
+ goto out;
+ }
++
++ /*AES_GCM_128, AES_GCM_192, AES_GCM_256*/
++ if(ealg_id == ESP_AES_GCM_8
++ || ealg_id == ESP_AES_GCM_12
++ || ealg_id == ESP_AES_GCM_16) {
++
++ /*AES-GCM length key length + 4 bytes (32 bits) */
++ if( p_ctx->eklen != 128
++ && p_ctx->eklen != 192
++ && p_ctx->eklen != 256 ) {
++ p_ctx->err="wrong encryption key length with AES-GCM";
++ goto out;
++ }
++ else {
++ /* increase key length by 4 bytes, RFC 4106 */
++ p_ctx->eklen = p_ctx->eklen + 4 * BITS_PER_BYTE;
++ }
++
++ }
++
+ DBG(DBG_CRYPT, DBG_log("parser_alg_info_add() "
+ "ealg_getbyname(\"%s\")=%d",
+ p_ctx->ealg_buf,
+diff --git a/lib/libopenswan/kernel_alg.c b/lib/libopenswan/kernel_alg.c
+index c611a11..b396109 100644
+--- a/lib/libopenswan/kernel_alg.c
++++ b/lib/libopenswan/kernel_alg.c
+@@ -150,6 +150,25 @@ kernel_alg_esp_enc_ok(int alg_id, unsigned int key_len,
+ if (!ret) goto out;
+
+ alg_p=&esp_ealg[alg_id];
++
++ if(alg_id == ESP_AES_GCM_8
++ || alg_id == ESP_AES_GCM_12
++ || alg_id == ESP_AES_GCM_16) {
++ if(key_len != 128 && key_len!=192 && key_len!=256 ) {
++
++ ugh = builddiag("kernel_alg_db_add() key_len is incorrect: alg_id=%d, "
++ "key_len=%d, alg_minbits=%d, alg_maxbits=%d",
++ alg_id, key_len,
++ alg_p->sadb_alg_minbits,
++ alg_p->sadb_alg_maxbits);
++ goto out;
++ }
++ else {
++ /* increase key length by 4 bytes (RFC 4106)*/
++ key_len = key_len + 4 * BITS_PER_BYTE;
++ }
++ }
++
+ /*
+ * test #2: if key_len specified, it must be in range
+ */
+diff --git a/programs/pluto/kernel_netlink.c b/programs/pluto/kernel_netlink.c
+index 830446e..895607c 100644
+--- a/programs/pluto/kernel_netlink.c
++++ b/programs/pluto/kernel_netlink.c
+@@ -1138,15 +1138,31 @@ linux_pfkey_add_aead(void)
+ struct sadb_alg alg;
+
+ alg.sadb_alg_ivlen = 8;
+- alg.sadb_alg_minbits = 128;
+- alg.sadb_alg_maxbits = 256;
++ alg.sadb_alg_minbits = 128 + 4 * BITS_PER_BYTE;
++ alg.sadb_alg_maxbits = 256 + 4 * BITS_PER_BYTE;
+
+ alg.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV8;
+ kernel_alg_add(SADB_SATYPE_ESP, SADB_EXT_SUPPORTED_ENCRYPT, &alg);
++
++ alg.sadb_alg_ivlen = 12;
++ alg.sadb_alg_minbits = 128 + 4 * BITS_PER_BYTE;
++ alg.sadb_alg_maxbits = 256 + 4 * BITS_PER_BYTE;
++
+ alg.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV12;
+ kernel_alg_add(SADB_SATYPE_ESP, SADB_EXT_SUPPORTED_ENCRYPT, &alg);
++
++ alg.sadb_alg_ivlen = 16;
++ alg.sadb_alg_minbits = 128 + 4 * BITS_PER_BYTE;
++ alg.sadb_alg_maxbits = 256 + 4 * BITS_PER_BYTE;
++
+ alg.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV16;
+ kernel_alg_add(SADB_SATYPE_ESP, SADB_EXT_SUPPORTED_ENCRYPT, &alg);
++
++ /* keeping aes-ccm behaviour intact as before */
++ alg.sadb_alg_ivlen = 8;
++ alg.sadb_alg_minbits = 128;
++ alg.sadb_alg_maxbits = 256;
++
+ alg.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV8;
+ kernel_alg_add(SADB_SATYPE_ESP, SADB_EXT_SUPPORTED_ENCRYPT, &alg);
+ alg.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV12;
+diff --git a/programs/pluto/plutoalg.c b/programs/pluto/plutoalg.c
+index e94cbea..1a5d73e 100644
+--- a/programs/pluto/plutoalg.c
++++ b/programs/pluto/plutoalg.c
+@@ -471,8 +471,18 @@ kernel_alg_db_add(struct db_context *db_ctx
+
+ /* add keylegth if specified in esp= string */
+ if (esp_info->esp_ealg_keylen) {
+- db_attr_add_values(db_ctx,
+- KEY_LENGTH, esp_info->esp_ealg_keylen);
++
++ if(esp_info->esp_ealg_id == ESP_AES_GCM_8
++ || esp_info->esp_ealg_id == ESP_AES_GCM_12
++ || esp_info->esp_ealg_id == ESP_AES_GCM_16 ) {
++
++ db_attr_add_values(db_ctx,
++ KEY_LENGTH, esp_info->esp_ealg_keylen - 4 * BITS_PER_BYTE);
++ }
++ else {
++ db_attr_add_values(db_ctx,
++ KEY_LENGTH, esp_info->esp_ealg_keylen );
++ }
+ }
+
+ } else if(policy & POLICY_AUTHENTICATE) {
+diff --git a/programs/pluto/spdb_v1_struct.c b/programs/pluto/spdb_v1_struct.c
+index 97faf35..14eb8d0 100644
+--- a/programs/pluto/spdb_v1_struct.c
++++ b/programs/pluto/spdb_v1_struct.c
+@@ -2368,7 +2368,12 @@ parse_ipsec_sa_body(
+ }
+ break;
+ #endif
+-
++ case ESP_AES_GCM_8:
++ case ESP_AES_GCM_12:
++ case ESP_AES_GCM_16:
++ loglog(RC_LOG_SERIOUS, "kernel algorithm (AES-GCM) does not like: %s", ugh);
++ continue;
++
+ case ESP_DES: /* NOT safe */
+ loglog(RC_LOG_SERIOUS, "1DES was proposed, it is insecure");
+ default:
+@@ -2594,7 +2599,13 @@ parse_ipsec_sa_body(
+ st->st_ah.attrs = ah_attrs;
+
+ st->st_esp.present = esp_seen;
+- if (esp_seen){
++ if (esp_seen) {
++ if(esp_attrs.transattrs.encrypt == ESP_AES_GCM_8
++ || esp_attrs.transattrs.encrypt == ESP_AES_GCM_12
++ || esp_attrs.transattrs.encrypt == ESP_AES_GCM_16 ) {
++ esp_attrs.transattrs.enckeylen = esp_attrs.transattrs.enckeylen + 4 * BITS_PER_BYTE;
++ }
++
+ st->st_esp.attrs = esp_attrs;
+ }
+
diff --git a/openswan-ikev1-ikev2-sha256.patch b/openswan-ikev1-ikev2-sha256.patch
new file mode 100644
index 0000000..ed86fcf
--- /dev/null
+++ b/openswan-ikev1-ikev2-sha256.patch
@@ -0,0 +1,165 @@
+From b024dfd54fb31f0b290e98bbae01813ecf3dd334 Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Fri, 3 Aug 2012 14:05:27 -0400
+Subject: ikev1/ikev2 sha2-256 related changes
+
+
+diff --git a/lib/libopenswan/constants.c b/lib/libopenswan/constants.c
+index e970509..c16ab74 100644
+--- a/lib/libopenswan/constants.c
++++ b/lib/libopenswan/constants.c
+@@ -1226,9 +1226,18 @@ const char *const trans_type_integ_name[]={
+ "auth-des-mac",
+ "auth-kpdk-md5",
+ "auth-aes-xcbc-96",
++ "AUTH_HMAC_MD5_128",
++ "AUTH_HMAC_SHA1_160",
++ "AUTH_AES_CMAC_96",
++ "AUTH_AES_128_GMAC",
++ "AUTH_AES_192_GMAC",
++ "AUTH_AES_256_GMAC",
++ "AUTH_HMAC_SHA2_256_128",
++ "AUTH_HMAC_SHA2_384_192",
++ "AUTH_HMAC_SHA2_512_256",
+ };
+ enum_names trans_type_integ_names =
+-{ IKEv2_AUTH_NONE, IKEv2_AUTH_AES_XCBC_96, trans_type_integ_name, NULL};
++{ IKEv2_AUTH_NONE, IKEv2_AUTH_HMAC_SHA2_512_256, trans_type_integ_name, NULL};
+
+ /* Transform-type Integrity */
+ const char *const trans_type_esn_name[]={
+diff --git a/programs/pluto/kernel.c b/programs/pluto/kernel.c
+index c8c8db8..fb1ad51 100644
+--- a/programs/pluto/kernel.c
++++ b/programs/pluto/kernel.c
+@@ -1746,16 +1746,17 @@ setup_half_ipsec_sa(struct state *st, bool inbound)
+ said_next->esatype = ET_ESP;
+ said_next->replay_window = kernel_ops->replay_window;
+ said_next->authalg = ei->authalg;
+- if( (said_next->authalg == AUTH_ALGORITHM_HMAC_SHA2_256) && (st->st_connection->sha2_truncbug)) {
+- if(kernel_ops->sha2_truncbug_support){
+- DBG_log(" authalg converted for sha2 truncation at 96bits instead of IETF's mandated 128bits");
+- /* We need to tell the kernel to mangle the sha2_256, as instructed by the user */
+- said_next->authalg = AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG;
+- } else {
++
++ if( (said_next->authalg == AUTH_ALGORITHM_HMAC_SHA2_256) && (st->st_connection->sha2_truncbug)) {
++ if(kernel_ops->sha2_truncbug_support){
++ DBG_log(" authalg converted for sha2 truncation at 96bits instead of IETF's mandated 128bits");
++ /* We need to tell the kernel to mangle the sha2_256, as instructed by the user */
++ said_next->authalg = AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG;
++ } else {
+ loglog(RC_LOG_SERIOUS, "Error: %s stack does not support sha2_truncbug=yes", kernel_ops->kern_name);
+- goto fail;
++ goto fail;
++ }
+ }
+- }
+ said_next->authkeylen = ei->authkeylen;
+ /* said_next->authkey = esp_dst_keymat + ei->enckeylen; */
+ said_next->authkey = esp_dst_keymat + key_len;
+diff --git a/programs/pluto/kernel_netlink.c b/programs/pluto/kernel_netlink.c
+index ef5cd2f..d917ea2 100644
+--- a/programs/pluto/kernel_netlink.c
++++ b/programs/pluto/kernel_netlink.c
+@@ -847,12 +847,11 @@ netlink_add_sa(struct kernel_sa *sa, bool replace)
+ * an earlier draft. The kernel then introduced a new struct xfrm_algo_auth to
+ * replace struct xfrm_algo to deal with this
+ */
+- if( (sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_256) ||
+- (sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG) ) {
++ if(sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG) {
+ struct xfrm_algo_auth algo;
+ DBG(DBG_NETKEY, DBG_log(" using new struct xfrm_algo_auth for XFRM message with explicit truncation for sha2_256"));
+ algo.alg_key_len = sa->authkeylen * BITS_PER_BYTE;
+- algo.alg_trunc_len = (sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG) ? 96 : 128;
++ algo.alg_trunc_len = 128;
+ attr->rta_type = XFRMA_ALG_AUTH_TRUNC;
+ attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->authkeylen);
+ sa->authalg = AUTH_ALGORITHM_HMAC_SHA2_256; /* fixup to the real number, not our private number */
+diff --git a/programs/pluto/spdb.h b/programs/pluto/spdb.h
+index 079b6dc..e36f0ba 100644
+--- a/programs/pluto/spdb.h
++++ b/programs/pluto/spdb.h
+@@ -188,6 +188,7 @@ extern void sa_v2_print(struct db_sa *f);
+ extern struct db_sa *sa_v2_convert(struct db_sa *f);
+ extern enum ikev2_trans_type_encr v1tov2_encr(int oakley);
+ extern enum ikev2_trans_type_integ v1tov2_integ(int oakley);
++extern enum ikev2_trans_type_integ v1phase2tov2child_integ(int ikev1_phase2_auth);
+ extern bool ikev2_acceptable_group(struct state *st, oakley_group_t group);
+
+
+diff --git a/programs/pluto/spdb_v2_struct.c b/programs/pluto/spdb_v2_struct.c
+index 25c686c..a744100 100644
+--- a/programs/pluto/spdb_v2_struct.c
++++ b/programs/pluto/spdb_v2_struct.c
+@@ -288,6 +288,21 @@ enum ikev2_trans_type_integ v1tov2_integ(int oakley)
+ }
+ }
+
++enum ikev2_trans_type_integ v1phase2tov2child_integ(int ikev1_phase2_auth)
++{
++ switch(ikev1_phase2_auth) {
++ case AUTH_ALGORITHM_HMAC_MD5:
++ return IKEv2_AUTH_HMAC_MD5_96;
++ case AUTH_ALGORITHM_HMAC_SHA1:
++ return IKEv2_AUTH_HMAC_SHA1_96;
++ case AUTH_ALGORITHM_HMAC_SHA2_256:
++ return IKEv2_AUTH_HMAC_SHA2_256_128;
++ default:
++ return IKEv2_AUTH_INVALID;
++ }
++}
++
++
+ static enum ikev2_trans_type_prf v1tov2_prf(int oakley)
+ {
+ switch(oakley) {
+@@ -385,7 +400,7 @@ struct db_sa *sa_v2_convert(struct db_sa *f)
+ } else {
+ switch(attr->type.ipsec) {
+ case AUTH_ALGORITHM:
+- dtfone->integ_transid = attr->val;
++ dtfone->integ_transid = v1phase2tov2child_integ(attr->val);
+ break;
+
+ case KEY_LENGTH:
+@@ -1233,7 +1248,7 @@ ikev2_parse_child_sa_body(
+ bool conjunction, gotmatch;
+ struct ikev2_prop winning_prop;
+ struct db_sa *p2alg;
+- struct trans_attrs ta;
++ struct trans_attrs ta, ta1;
+ struct connection *c = st->st_connection;
+ struct ikev2_transform_list itl0, *itl;
+
+@@ -1250,6 +1265,7 @@ ikev2_parse_child_sa_body(
+ gotmatch = FALSE;
+ conjunction = FALSE;
+ zero(&ta);
++ zero(&ta1);
+
+ while(np == ISAKMP_NEXT_P) {
+ /*
+@@ -1372,6 +1388,12 @@ ikev2_parse_child_sa_body(
+ * algorithms.
+ */
+ ta.integ_hash = itl->integ_transforms[itl->integ_i];
++
++ /* here we obtain auth value for esp,
++ * but loosse what is correct to be sent in the propoasl
++ * so preserve the winning proposal.
++ */
++ ta1 = ta;
+ ta.integ_hash = alg_info_esp_v2tov1aa(ta.integ_hash);
+
+ st->st_esp.attrs.transattrs = ta;
+@@ -1386,7 +1408,7 @@ ikev2_parse_child_sa_body(
+ if (r_sa_pbs != NULL)
+ {
+ return ikev2_emit_winning_sa(st, r_sa_pbs
+- , ta
++ , ta1
+ , /*parentSA*/FALSE
+ , winning_prop);
+ }
diff --git a/openswan-ikev1-ikev2-sha384-512.patch b/openswan-ikev1-ikev2-sha384-512.patch
new file mode 100644
index 0000000..af26027
--- /dev/null
+++ b/openswan-ikev1-ikev2-sha384-512.patch
@@ -0,0 +1,633 @@
+From 8467b53a014ebf6dcd400c259d2bb2fa8991df3f Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Fri, 3 Aug 2012 14:41:50 -0400
+Subject: ikev1/ikev2 sha2(384, 512) changes
+
+
+diff --git a/include/ietf_constants.h b/include/ietf_constants.h
+index 28df5a1..d065509 100644
+--- a/include/ietf_constants.h
++++ b/include/ietf_constants.h
+@@ -605,7 +605,6 @@ enum ikev2_trans_type_integ {
+ IKEv2_AUTH_HMAC_SHA2_512_256 = 14, /* RFC4306 */
+ /* 15 - 1023 Reserved to IANA RFC4306 */
+ /* 1024 - 65535 Private Use RFC4306 */
+- IKEv2_AUTH_HMAC_SHA2_256_128_TRUNCBUG = 252, /* our own value */
+ IKEv2_AUTH_INVALID =65536
+ };
+
+@@ -795,6 +794,8 @@ enum ikev1_auth_attribute {
+ AUTH_ALGORITHM_AES_CBC=9,
+ AUTH_ALGORITHM_NULL_KAME=251, /* why do we load this ? */
+ AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG=252,
++ AUTH_ALGORITHM_HMAC_SHA2_384_TRUNCBUG=253,
++ AUTH_ALGORITHM_HMAC_SHA2_512_TRUNCBUG=254,
+ };
+
+ typedef u_int16_t ipsec_auth_t;
+diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h
+index 2a53c3d..6cb3b81 100644
+--- a/include/linux/pfkeyv2.h
++++ b/include/linux/pfkeyv2.h
+@@ -279,6 +279,8 @@ struct sadb_x_nat_t_port {
+ #define SADB_X_AALG_RIPEMD160HMAC 8
+ #define SADB_X_AALG_NULL 251 /* kame */
+ #define SADB_X_AALG_SHA2_256HMAC_TRUNCBUG 252
++#define SADB_X_AALG_SHA2_384HMAC_TRUNCBUG 253
++#define SADB_X_AALG_SHA2_512HMAC_TRUNCBUG 254
+ #define SADB_AALG_MAX 255 /* while the AUTH_ALGORITHM is two octets, what is the SADB_AALG? */
+
+ /* Encryption algorithms */
+diff --git a/lib/libopenswan/alg_info.c b/lib/libopenswan/alg_info.c
+index 320cbd4..796fbfb 100644
+--- a/lib/libopenswan/alg_info.c
++++ b/lib/libopenswan/alg_info.c
+@@ -84,12 +84,10 @@ alg_info_esp_v2tov1aa(enum ikev2_trans_type_integ ti)
+ return AUTH_ALGORITHM_HMAC_SHA1;
+ case IKEv2_AUTH_HMAC_SHA2_256_128:
+ return AUTH_ALGORITHM_HMAC_SHA2_256;
+- case IKEv2_AUTH_HMAC_SHA2_256_128_TRUNCBUG:
+- return AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG;
+ case IKEv2_AUTH_HMAC_SHA2_384_192:
+- return AUTH_ALGORITHM_HMAC_SHA2_256;
++ return AUTH_ALGORITHM_HMAC_SHA2_384;
+ case IKEv2_AUTH_HMAC_SHA2_512_256:
+- return AUTH_ALGORITHM_HMAC_SHA2_256;
++ return AUTH_ALGORITHM_HMAC_SHA2_512;
+
+ /* invalid or not yet supported */
+ case IKEv2_AUTH_DES_MAC:
+@@ -635,12 +633,6 @@ parser_alg_info_add(struct parser_context *p_ctx
+ goto out;
+ }
+
+-#ifdef HAVE_LIBNSS
+- if ( Pluto_IsFIPS() && ((aalg_id == OAKLEY_SHA2_256 ) ||(aalg_id == OAKLEY_SHA2_384 ) || (aalg_id == OAKLEY_SHA2_512 )) ) {
+- p_ctx->err="SHA2 Not supported in FIPS mode with NSS";
+- goto out;
+- }
+-#endif
+ DBG(DBG_CRYPT, DBG_log("parser_alg_info_add() "
+ "aalg_getbyname(\"%s\")=%d",
+ p_ctx->aalg_buf,
+diff --git a/linux/include/openswan/pfkeyv2.h b/linux/include/openswan/pfkeyv2.h
+index a3b810c..27a8849 100644
+--- a/linux/include/openswan/pfkeyv2.h
++++ b/linux/include/openswan/pfkeyv2.h
+@@ -276,7 +276,9 @@ enum sadb_aalg {
+ K_SADB_X_AALG_SHA2_256HMAC=SADB_X_AALG_SHA2_256HMAC,
+ K_SADB_X_AALG_SHA2_256HMAC_TRUNCBUG=SADB_X_AALG_SHA2_256HMAC_TRUNCBUG,
+ K_SADB_X_AALG_SHA2_384HMAC=SADB_X_AALG_SHA2_384HMAC,
++ K_SADB_X_AALG_SHA2_384HMAC_TRUNCBUG=SADB_X_AALG_SHA2_384HMAC_TRUNCBUG,
+ K_SADB_X_AALG_SHA2_512HMAC=SADB_X_AALG_SHA2_512HMAC,
++ K_SADB_X_AALG_SHA2_512HMAC_TRUNCBUG=SADB_X_AALG_SHA2_512HMAC_TRUNCBUG,
+ K_SADB_X_AALG_RIPEMD160HMAC=SADB_X_AALG_RIPEMD160HMAC,
+ K_SADB_X_AALG_NULL=SADB_X_AALG_NULL,
+ };
+diff --git a/programs/pluto/crypt_dh.c b/programs/pluto/crypt_dh.c
+index a350acf..e6f6f2e 100644
+--- a/programs/pluto/crypt_dh.c
++++ b/programs/pluto/crypt_dh.c
+@@ -296,7 +296,7 @@ skeyid_preshared(const chunk_t pss
+ chunk_t nir;
+ int k;
+ CK_MECHANISM_TYPE mechanism;
+- u_char buf1[HMAC_BUFSIZE], buf2[HMAC_BUFSIZE];
++ u_char buf1[HMAC_BUFSIZE*2], buf2[HMAC_BUFSIZE*2];
+ chunk_t buf1_chunk, buf2_chunk;
+ PK11SymKey *shared, *skeyid;
+
+@@ -317,9 +317,9 @@ skeyid_preshared(const chunk_t pss
+ memcpy(nir.ptr, ni.ptr, ni.len);
+ memcpy(nir.ptr+ ni.len, nr.ptr, nr.len);
+
+- memset(buf1, '\0', HMAC_BUFSIZE);
++ memset(buf1, '\0', HMAC_BUFSIZE*2);
+
+- if (pss.len <= HMAC_BUFSIZE)
++ if (pss.len <= hasher->hash_block_size)
+ {
+ memcpy(buf1, pss.ptr, pss.len);
+ }
+@@ -330,9 +330,9 @@ skeyid_preshared(const chunk_t pss
+ hasher->hash_final(buf1, &ctx.hash_ctx);
+ }
+
+- memcpy(buf2, buf1, HMAC_BUFSIZE);
++ memcpy(buf2, buf1, hasher->hash_block_size);
+
+- for (k = 0; k < HMAC_BUFSIZE; k++)
++ for (k = 0; k < hasher->hash_block_size; k++)
+ {
+ buf1[k] ^= HMAC_IPAD;
+ buf2[k] ^= HMAC_OPAD;
+@@ -342,16 +342,16 @@ skeyid_preshared(const chunk_t pss
+
+ mechanism=nss_key_derivation_mech(hasher);
+ buf1_chunk.ptr=buf1;
+- buf1_chunk.len=HMAC_BUFSIZE;
++ buf1_chunk.len=hasher->hash_block_size;
+
+ buf2_chunk.ptr=buf2;
+- buf2_chunk.len=HMAC_BUFSIZE;
++ buf2_chunk.len=hasher->hash_block_size;
+
+ PK11SymKey *tkey4 = pk11_derive_wrapper_osw(shared, CKM_CONCATENATE_DATA_AND_BASE, buf1_chunk, CKM_EXTRACT_KEY_FROM_KEY, CKA_DERIVE, 0);
+ /* nss_symkey_log(tkey4, "pss+ipad+shared"); */
+
+ CK_EXTRACT_PARAMS bs=0;
+- PK11SymKey *tkey5 = pk11_extract_derive_wrapper_osw(tkey4, bs, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, HMAC_BUFSIZE);
++ PK11SymKey *tkey5 = pk11_extract_derive_wrapper_osw(tkey4, bs, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, hasher->hash_block_size);
+ /* nss_symkey_log(tkey5, "pss+ipad"); */
+
+ PK11SymKey *tkey6 = pk11_derive_wrapper_osw(tkey5, CKM_CONCATENATE_BASE_AND_DATA, nir, mechanism, CKA_DERIVE, 0);
+@@ -405,7 +405,7 @@ skeyid_digisig(const chunk_t ni
+ #ifdef HAVE_LIBNSS
+ int k;
+ CK_MECHANISM_TYPE mechanism;
+- u_char buf1[HMAC_BUFSIZE], buf2[HMAC_BUFSIZE];
++ u_char buf1[HMAC_BUFSIZE*2], buf2[HMAC_BUFSIZE*2];
+ chunk_t buf1_chunk, buf2_chunk;
+ PK11SymKey *shared, *skeyid;
+ #endif
+@@ -435,8 +435,8 @@ skeyid_digisig(const chunk_t ni
+ hmac_final_chunk(*skeyid_chunk, "st_skeyid in skeyid_digisig()", &ctx);
+ DBG(DBG_CRYPT, DBG_dump_chunk("keyid: ", *skeyid_chunk));
+ #else
+- memset(buf1, '\0', HMAC_BUFSIZE);
+- if (nir.len <= HMAC_BUFSIZE)
++ memset(buf1, '\0', HMAC_BUFSIZE*2);
++ if (nir.len <= hasher->hash_block_size)
+ {
+ memcpy(buf1, nir.ptr, nir.len);
+ }
+@@ -447,9 +447,9 @@ skeyid_digisig(const chunk_t ni
+ hasher->hash_final(buf1, &ctx.hash_ctx);
+ }
+
+- memcpy(buf2, buf1, HMAC_BUFSIZE);
++ memcpy(buf2, buf1, hasher->hash_block_size);
+
+- for (k = 0; k < HMAC_BUFSIZE; k++)
++ for (k = 0; k < hasher->hash_block_size; k++)
+ {
+ buf1[k] ^= HMAC_IPAD;
+ buf2[k] ^= HMAC_OPAD;
+@@ -458,10 +458,10 @@ skeyid_digisig(const chunk_t ni
+ pfree(nir.ptr);
+ mechanism=nss_key_derivation_mech(hasher);
+ buf1_chunk.ptr=buf1;
+- buf1_chunk.len=HMAC_BUFSIZE;
++ buf1_chunk.len=hasher->hash_block_size;
+
+ buf2_chunk.ptr=buf2;
+- buf2_chunk.len=HMAC_BUFSIZE;
++ buf2_chunk.len=hasher->hash_block_size;
+
+ PK11SymKey *tkey1 = pk11_derive_wrapper_osw(shared, CKM_CONCATENATE_DATA_AND_BASE, buf1_chunk, mechanism, CKA_DERIVE, 0);
+ PK11SymKey *tkey2 = PK11_Derive_osw(tkey1, mechanism, NULL, CKM_CONCATENATE_DATA_AND_BASE, CKA_DERIVE, 0);
+@@ -562,9 +562,9 @@ calc_skeyids_iv(struct pcr_skeyid_q *skq
+ CK_OBJECT_HANDLE keyhandle;
+ SECItem param, param1;
+
+- hmac_opad = hmac_pads(HMAC_OPAD,HMAC_BUFSIZE);
+- hmac_ipad = hmac_pads(HMAC_IPAD,HMAC_BUFSIZE);
+- hmac_pad = hmac_pads(0x00,HMAC_BUFSIZE-hasher->hash_digest_len);
++ hmac_opad = hmac_pads(HMAC_OPAD,hasher->hash_block_size);
++ hmac_ipad = hmac_pads(HMAC_IPAD,hasher->hash_block_size);
++ hmac_pad = hmac_pads(0x00,hasher->hash_block_size-hasher->hash_digest_len);
+ hmac_zerobyte = hmac_pads(0x00,1);
+ hmac_val1 = hmac_pads(0x01,1);
+ hmac_val2 = hmac_pads(0x02,1);
+@@ -573,7 +573,7 @@ calc_skeyids_iv(struct pcr_skeyid_q *skq
+
+ /*Deriving SKEYID_d = hmac_xxx(SKEYID, g^xy | CKY-I | CKY-R | 0) */
+ PK11SymKey *tkey1 = pk11_derive_wrapper_osw(skeyid, CKM_CONCATENATE_BASE_AND_DATA
+- , hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, HMAC_BUFSIZE);
++ , hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, hasher->hash_block_size);
+
+ PR_ASSERT(tkey1!=NULL);
+
+@@ -742,7 +742,7 @@ calc_skeyids_iv(struct pcr_skeyid_q *skq
+ /* nss_symkey_log(skeyid_e, "skeyid_e"); */
+
+ PK11SymKey *tkey25 = pk11_derive_wrapper_osw(skeyid_e, CKM_CONCATENATE_BASE_AND_DATA
+- , hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, HMAC_BUFSIZE);
++ , hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, hasher->hash_block_size);
+ PR_ASSERT(tkey25!=NULL);
+
+ PK11SymKey *tkey26 = pk11_derive_wrapper_osw(tkey25, CKM_XOR_BASE_AND_DATA
+@@ -776,7 +776,7 @@ calc_skeyids_iv(struct pcr_skeyid_q *skq
+ i += hasher->hash_digest_len;
+
+ PK11SymKey *tkey32 = pk11_derive_wrapper_osw(skeyid_e, CKM_CONCATENATE_BASE_AND_DATA
+- , hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, HMAC_BUFSIZE);
++ , hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, hasher->hash_block_size);
+ PR_ASSERT(tkey32!=NULL);
+
+ PK11SymKey *tkey33 = pk11_derive_wrapper_osw(tkey32, CKM_XOR_BASE_AND_DATA
+@@ -1242,9 +1242,9 @@ calc_skeyseed_v2(struct pcr_skeyid_q *skq
+ passert(encrypter);
+
+
+- hmac_opad = hmac_pads(HMAC_OPAD,HMAC_BUFSIZE);
+- hmac_ipad = hmac_pads(HMAC_IPAD,HMAC_BUFSIZE);
+- hmac_pad_prf = hmac_pads(0x00,HMAC_BUFSIZE-hasher->hash_digest_len);
++ hmac_opad = hmac_pads(HMAC_OPAD,hasher->hash_block_size);
++ hmac_ipad = hmac_pads(HMAC_IPAD,hasher->hash_block_size);
++ hmac_pad_prf = hmac_pads(0x00,hasher->hash_block_size-hasher->hash_digest_len);
+
+
+ /* generate SKEYSEED from key=(Ni|Nr), hash of shared */
+@@ -1328,7 +1328,7 @@ calc_skeyseed_v2(struct pcr_skeyid_q *skq
+
+ PK11SymKey *finalkey;
+ PK11SymKey *tkey1 = pk11_derive_wrapper_osw(skeyseed_k, CKM_CONCATENATE_BASE_AND_DATA
+- , hmac_pad_prf,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, HMAC_BUFSIZE);
++ , hmac_pad_prf,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, hasher->hash_block_size);
+ PR_ASSERT(tkey1!=NULL);
+
+
+diff --git a/programs/pluto/crypto.c b/programs/pluto/crypto.c
+index d9bde44..1e568c9 100644
+--- a/programs/pluto/crypto.c
++++ b/programs/pluto/crypto.c
+@@ -127,6 +127,7 @@ static struct hash_desc crypto_hasher_md5 =
+ hash_key_size: MD5_DIGEST_SIZE,
+ hash_digest_len: MD5_DIGEST_SIZE,
+ hash_integ_len: 0, /*Not applicable*/
++ hash_block_size: HMAC_BUFSIZE,
+ hash_init: (void (*)(void *)) osMD5Init,
+ hash_update: (void (*)(void *, const u_int8_t *, size_t)) osMD5Update,
+ hash_final: (void (*)(u_char *, void *)) osMD5Final,
+@@ -143,7 +144,8 @@ static struct hash_desc crypto_integ_md5 =
+ hash_ctx_size: sizeof(MD5_CTX),
+ hash_key_size: MD5_DIGEST_SIZE,
+ hash_digest_len: MD5_DIGEST_SIZE,
+- hash_integ_len: MD5_DIGEST_SIZE_96,
++ hash_integ_len: MD5_DIGEST_SIZE_96,
++ hash_block_size: HMAC_BUFSIZE,
+ hash_init: (void (*)(void *)) osMD5Init,
+ hash_update: (void (*)(void *, const u_int8_t *, size_t)) osMD5Update,
+ hash_final: (void (*)(u_char *, void *)) osMD5Final,
+@@ -161,6 +163,7 @@ static struct hash_desc crypto_hasher_sha1 =
+ hash_key_size: SHA1_DIGEST_SIZE,
+ hash_digest_len: SHA1_DIGEST_SIZE,
+ hash_integ_len: 0, /*Not applicable*/
++ hash_block_size: HMAC_BUFSIZE,
+ hash_init: (void (*)(void *)) SHA1Init,
+ hash_update: (void (*)(void *, const u_int8_t *, size_t)) SHA1Update,
+ hash_final: (void (*)(u_char *, void *)) SHA1Final,
+@@ -178,6 +181,7 @@ static struct hash_desc crypto_integ_sha1 =
+ hash_key_size: SHA1_DIGEST_SIZE,
+ hash_digest_len: SHA1_DIGEST_SIZE,
+ hash_integ_len: SHA1_DIGEST_SIZE_96,
++ hash_block_size: HMAC_BUFSIZE,
+ hash_init: (void (*)(void *)) SHA1Init,
+ hash_update: (void (*)(void *, const u_int8_t *, size_t)) SHA1Update,
+ hash_final: (void (*)(u_char *, void *)) SHA1Final,
+diff --git a/programs/pluto/hmac.c b/programs/pluto/hmac.c
+index 1f129f7..2c009a4 100644
+--- a/programs/pluto/hmac.c
++++ b/programs/pluto/hmac.c
+@@ -71,11 +71,11 @@ hmac_init(struct hmac_ctx *ctx,
+ memcpy(&symkey, key, key_len);
+ klen = PK11_GetKeyLength(symkey);
+
+- hmac_opad = hmac_pads(HMAC_OPAD,HMAC_BUFSIZE);
+- hmac_ipad = hmac_pads(HMAC_IPAD,HMAC_BUFSIZE);
+- hmac_pad = hmac_pads(0x00,HMAC_BUFSIZE-klen);
++ hmac_opad = hmac_pads(HMAC_OPAD, h->hash_block_size);
++ hmac_ipad = hmac_pads(HMAC_IPAD,h->hash_block_size);
++ hmac_pad = hmac_pads(0x00,h->hash_block_size-klen);
+
+- if(klen > HMAC_BUFSIZE)
++ if(klen > h->hash_block_size)
+ {
+ tkey1 = PK11_Derive_osw(symkey, nss_key_derivation_mech(h)
+ , NULL, CKM_CONCATENATE_BASE_AND_DATA, CKA_DERIVE, 0);
+@@ -86,7 +86,7 @@ hmac_init(struct hmac_ctx *ctx,
+ }
+
+ PK11SymKey *tkey2 = pk11_derive_wrapper_osw(tkey1, CKM_CONCATENATE_BASE_AND_DATA
+- , hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, HMAC_BUFSIZE);
++ , hmac_pad,CKM_XOR_BASE_AND_DATA, CKA_DERIVE, h->hash_block_size);
+
+ PR_ASSERT(tkey2!=NULL);
+ ctx->ikey = pk11_derive_wrapper_osw(tkey2, CKM_XOR_BASE_AND_DATA
+@@ -266,7 +266,7 @@ PK11SymKey * PK11_Derive_osw(PK11SymKey *base, CK_MECHANISM_TYPE mechanism
+ {
+ SECOidTag oid;
+ PK11Context *ctx;
+- unsigned char dkey[HMAC_BUFSIZE];
++ unsigned char dkey[HMAC_BUFSIZE*2];
+ SECItem dkey_param;
+ SECStatus status;
+ unsigned int len=0;
+diff --git a/programs/pluto/ike_alg.h b/programs/pluto/ike_alg.h
+index 08b125e..8f56014 100644
+--- a/programs/pluto/ike_alg.h
++++ b/programs/pluto/ike_alg.h
+@@ -38,6 +38,7 @@ struct hash_desc {
+ size_t hash_ctx_size;
+ size_t hash_digest_len;
+ size_t hash_integ_len; /*truncated output len when used as an integrity algorithm in IKEV2*/
++ size_t hash_block_size;
+ void (*hash_init)(void *ctx);
+ hash_update_t hash_update;
+ void (*hash_final)(u_int8_t *out, void *ctx);
+diff --git a/programs/pluto/ike_alg_sha2.c b/programs/pluto/ike_alg_sha2.c
+index cbcfdc4..09122ef 100644
+--- a/programs/pluto/ike_alg_sha2.c
++++ b/programs/pluto/ike_alg_sha2.c
+@@ -31,6 +31,23 @@ static void sha256_hash_final(u_char *hash, sha256_context *ctx)
+ memcpy(hash, &ctx->sha_out[0], SHA2_256_DIGEST_SIZE);
+ #endif
+ }
++
++static void sha384_hash_final(u_char *hash, sha512_context *ctx)
++{
++#ifdef HAVE_LIBNSS
++ unsigned int len;
++ SECStatus s;
++ s = PK11_DigestFinal(ctx->ctx_nss, hash, &len, SHA2_384_DIGEST_SIZE);
++ PR_ASSERT(len==SHA2_384_DIGEST_SIZE);
++ PR_ASSERT(s==SECSuccess);
++ PK11_DestroyContext(ctx->ctx_nss, PR_TRUE);
++ DBG(DBG_CRYPT, DBG_log("NSS SHA 384 hash final : end"));
++#else
++ sha384_final(ctx);
++ memcpy(hash, &ctx->sha_out[0], SHA2_384_DIGEST_SIZE);
++#endif
++}
++
+ static void sha512_hash_final(u_char *hash, sha512_context *ctx)
+ {
+ #ifdef HAVE_LIBNSS
+@@ -46,6 +63,7 @@ static void sha512_hash_final(u_char *hash, sha512_context *ctx)
+ memcpy(hash, &ctx->sha_out[0], SHA2_512_DIGEST_SIZE);
+ #endif
+ }
++
+ struct hash_desc hash_desc_sha2_256 = {
+ common:{officname: "sha256",
+ algo_type: IKE_ALG_HASH,
+@@ -56,6 +74,7 @@ struct hash_desc hash_desc_sha2_256 = {
+ hash_key_size: SHA2_256_DIGEST_SIZE,
+ hash_digest_len: SHA2_256_DIGEST_SIZE,
+ hash_integ_len: 0, /*Not applicable*/
++ hash_block_size: HMAC_BUFSIZE,
+ hash_init: (void (*)(void *))sha256_init,
+ hash_update: (void (*)(void *, const u_char *, size_t ))sha256_write,
+ hash_final:(void (*)(u_char *, void *))sha256_hash_final,
+@@ -71,35 +90,93 @@ struct hash_desc integ_desc_sha2_256 = {
+ hash_key_size: SHA2_256_DIGEST_SIZE,
+ hash_digest_len: SHA2_256_DIGEST_SIZE,
+ hash_integ_len: SHA2_256_DIGEST_SIZE/2,
++ hash_block_size: HMAC_BUFSIZE,
+ hash_init: (void (*)(void *))sha256_init,
+ hash_update: (void (*)(void *, const u_char *, size_t ))sha256_write,
+ hash_final:(void (*)(u_char *, void *))sha256_hash_final,
+ };
+
++struct hash_desc hash_desc_sha2_384 = {
++ common:{officname: "sha384",
++ algo_type: IKE_ALG_HASH,
++ algo_id: OAKLEY_SHA2_384,
++ algo_v2id: IKEv2_PRF_HMAC_SHA2_384,
++ algo_next: NULL, },
++ hash_ctx_size: sizeof(sha512_context),
++ hash_key_size: SHA2_384_DIGEST_SIZE,
++ hash_digest_len: SHA2_384_DIGEST_SIZE,
++ hash_integ_len: 0, /*Not applicable*/
++ hash_block_size: HMAC_BUFSIZE*2,
++ hash_init: (void (*)(void *))sha384_init,
++ hash_update: (void (*)(void *, const u_char *, size_t ))sha512_write,
++ hash_final:(void (*)(u_char *, void *))sha384_hash_final,
++};
++
++struct hash_desc integ_desc_sha2_384 = {
++ common:{officname: "sha384",
++ algo_type: IKE_ALG_INTEG,
++ algo_id: OAKLEY_SHA2_384,
++ algo_v2id: IKEv2_AUTH_HMAC_SHA2_384_192,
++ algo_next: NULL, },
++ hash_ctx_size: sizeof(sha512_context),
++ hash_key_size: SHA2_384_DIGEST_SIZE,
++ hash_digest_len: SHA2_384_DIGEST_SIZE,
++ hash_integ_len: SHA2_384_DIGEST_SIZE/2,
++ hash_block_size: HMAC_BUFSIZE*2,
++ hash_init: (void (*)(void *))sha384_init,
++ hash_update: (void (*)(void *, const u_char *, size_t ))sha512_write,
++ hash_final:(void (*)(u_char *, void *))sha384_hash_final,
++};
++
+ struct hash_desc hash_desc_sha2_512 = {
+ common:{officname: "sha512",
+ algo_type: IKE_ALG_HASH,
+ algo_id: OAKLEY_SHA2_512,
++ algo_v2id: IKEv2_PRF_HMAC_SHA2_512,
+ algo_next: NULL, },
+ hash_ctx_size: sizeof(sha512_context),
+- hash_key_size: 0,
++ hash_key_size: SHA2_512_DIGEST_SIZE,
+ hash_digest_len: SHA2_512_DIGEST_SIZE,
+ hash_integ_len: 0, /*Not applicable*/
++ hash_block_size: HMAC_BUFSIZE*2,
+ hash_init: (void (*)(void *))sha512_init,
+ hash_update: (void (*)(void *, const u_char *, size_t ))sha512_write,
+ hash_final:(void (*)(u_char *, void *))sha512_hash_final,
+ };
++
++struct hash_desc integ_desc_sha2_512 = {
++ common:{officname: "sha512",
++ algo_type: IKE_ALG_INTEG,
++ algo_id: OAKLEY_SHA2_512,
++ algo_v2id: IKEv2_AUTH_HMAC_SHA2_512_256,
++ algo_next: NULL, },
++ hash_ctx_size: sizeof(sha512_context),
++ hash_key_size: SHA2_512_DIGEST_SIZE,
++ hash_digest_len: SHA2_512_DIGEST_SIZE,
++ hash_integ_len: SHA2_512_DIGEST_SIZE/2,
++ hash_block_size: HMAC_BUFSIZE*2,
++ hash_init: (void (*)(void *))sha512_init,
++ hash_update: (void (*)(void *, const u_char *, size_t ))sha512_write,
++ hash_final:(void (*)(u_char *, void *))sha512_hash_final,
++};
++
+ int ike_alg_sha2_init(void);
+ int
+ ike_alg_sha2_init(void)
+ {
+ int ret;
+ ret = ike_alg_register_hash(&hash_desc_sha2_512);
+- if (!ret){
+- ret = ike_alg_register_hash(&hash_desc_sha2_256);
+- ike_alg_add((struct ike_alg *) &integ_desc_sha2_256);
+- }
++ if (ret)
++ goto out;
++ ret = ike_alg_register_hash(&hash_desc_sha2_384);
++ if (ret)
++ goto out;
++ ret = ike_alg_register_hash(&hash_desc_sha2_256);
+
++ ike_alg_add((struct ike_alg *) &integ_desc_sha2_256);
++ ike_alg_add((struct ike_alg *) &integ_desc_sha2_384);
++ ike_alg_add((struct ike_alg *) &integ_desc_sha2_512);
++out:
+ return ret;
+ }
+ /*
+diff --git a/programs/pluto/ikev2_crypto.c b/programs/pluto/ikev2_crypto.c
+index c924910..db3d6c9 100644
+--- a/programs/pluto/ikev2_crypto.c
++++ b/programs/pluto/ikev2_crypto.c
+@@ -65,10 +65,8 @@ void ikev2_derive_child_keys(struct state *st, enum phase1_role role)
+
+ passert(ipi->attrs.transattrs.ei != NULL);
+ memset(&childsacalc, 0, sizeof(childsacalc));
+- childsacalc.prf_hasher = (struct hash_desc *)
+- ike_alg_ikev2_find(IKE_ALG_HASH
+- , IKEv2_PRF_HMAC_SHA1, 0);
+-
++ childsacalc.prf_hasher = st->st_oakley.prf_hasher;
++
+ setchunk(childsacalc.ni, st->st_ni.ptr, st->st_ni.len);
+ setchunk(childsacalc.nr, st->st_nr.ptr, st->st_nr.len);
+ childsacalc.spii.len=0;
+diff --git a/programs/pluto/kernel.c b/programs/pluto/kernel.c
+index fb1ad51..9924078 100644
+--- a/programs/pluto/kernel.c
++++ b/programs/pluto/kernel.c
+@@ -1747,14 +1747,31 @@ setup_half_ipsec_sa(struct state *st, bool inbound)
+ said_next->replay_window = kernel_ops->replay_window;
+ said_next->authalg = ei->authalg;
+
+- if( (said_next->authalg == AUTH_ALGORITHM_HMAC_SHA2_256) && (st->st_connection->sha2_truncbug)) {
+- if(kernel_ops->sha2_truncbug_support){
++ if( (said_next->authalg == AUTH_ALGORITHM_HMAC_SHA2_256
++ || said_next->authalg == AUTH_ALGORITHM_HMAC_SHA2_384
++ || said_next->authalg == AUTH_ALGORITHM_HMAC_SHA2_512 ) && (st->st_connection->sha2_truncbug)) {
++ if(kernel_ops->sha2_truncbug_support) {
+ DBG_log(" authalg converted for sha2 truncation at 96bits instead of IETF's mandated 128bits");
+ /* We need to tell the kernel to mangle the sha2_256, as instructed by the user */
+- said_next->authalg = AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG;
++ switch(said_next->authalg)
++ {
++ case AUTH_ALGORITHM_HMAC_SHA2_256:
++ said_next->authalg = AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG;
++ break;
++ case AUTH_ALGORITHM_HMAC_SHA2_384:
++ said_next->authalg = AUTH_ALGORITHM_HMAC_SHA2_384_TRUNCBUG;
++ break;
++ case AUTH_ALGORITHM_HMAC_SHA2_512:
++ said_next->authalg = AUTH_ALGORITHM_HMAC_SHA2_512_TRUNCBUG;
++ break;
++ default:
++ DBG_log("auth truncation: control should not reach here");
++ break;
++ }
++
+ } else {
+- loglog(RC_LOG_SERIOUS, "Error: %s stack does not support sha2_truncbug=yes", kernel_ops->kern_name);
+- goto fail;
++ loglog(RC_LOG_SERIOUS, "Error: %s stack does not support sha2_truncbug=yes", kernel_ops->kern_name);
++ goto fail;
+ }
+ }
+ said_next->authkeylen = ei->authkeylen;
+diff --git a/programs/pluto/kernel_netlink.c b/programs/pluto/kernel_netlink.c
+index d917ea2..830446e 100644
+--- a/programs/pluto/kernel_netlink.c
++++ b/programs/pluto/kernel_netlink.c
+@@ -145,9 +145,10 @@ static sparse_names aalg_list = {
+ { SADB_AALG_SHA1HMAC, "sha1" },
+ { SADB_X_AALG_SHA2_256HMAC, "sha256" },
+ { SADB_X_AALG_SHA2_256HMAC_TRUNCBUG, "hmac(sha256)" },
+- { SADB_X_AALG_SHA2_256HMAC, "hmac(sha256)" },
+- { SADB_X_AALG_SHA2_384HMAC, "hmac(sha384)" },
+- { SADB_X_AALG_SHA2_512HMAC, "hmac(sha512)" },
++ { SADB_X_AALG_SHA2_384HMAC, "sha384" },
++ { SADB_X_AALG_SHA2_384HMAC_TRUNCBUG, "hmac(sha384)" },
++ { SADB_X_AALG_SHA2_512HMAC, "sha512" },
++ { SADB_X_AALG_SHA2_512HMAC_TRUNCBUG, "hmac(sha512)" },
+ { SADB_X_AALG_RIPEMD160HMAC, "ripemd160" },
+ { 0, sparse_end }
+ };
+@@ -847,14 +848,34 @@ netlink_add_sa(struct kernel_sa *sa, bool replace)
+ * an earlier draft. The kernel then introduced a new struct xfrm_algo_auth to
+ * replace struct xfrm_algo to deal with this
+ */
+- if(sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG) {
++ if(sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG
++ || sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_384_TRUNCBUG
++ || sa->authalg == AUTH_ALGORITHM_HMAC_SHA2_512_TRUNCBUG ) {
+ struct xfrm_algo_auth algo;
+- DBG(DBG_NETKEY, DBG_log(" using new struct xfrm_algo_auth for XFRM message with explicit truncation for sha2_256"));
++ DBG(DBG_NETKEY, DBG_log(" using new struct xfrm_algo_auth for XFRM message with explicit truncation for sha2_256/384/512"));
+ algo.alg_key_len = sa->authkeylen * BITS_PER_BYTE;
+- algo.alg_trunc_len = 128;
+ attr->rta_type = XFRMA_ALG_AUTH_TRUNC;
+ attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->authkeylen);
+- sa->authalg = AUTH_ALGORITHM_HMAC_SHA2_256; /* fixup to the real number, not our private number */
++
++ switch(sa->authalg)
++ {
++ case AUTH_ALGORITHM_HMAC_SHA2_256_TRUNCBUG:
++ algo.alg_trunc_len = 128;
++ sa->authalg = AUTH_ALGORITHM_HMAC_SHA2_256;
++ break;
++ case AUTH_ALGORITHM_HMAC_SHA2_384_TRUNCBUG:
++ algo.alg_trunc_len = 192;
++ sa->authalg = AUTH_ALGORITHM_HMAC_SHA2_384;
++ break;
++ case AUTH_ALGORITHM_HMAC_SHA2_512_TRUNCBUG:
++ algo.alg_trunc_len = 256;
++ sa->authalg = AUTH_ALGORITHM_HMAC_SHA2_512;
++ break;
++ default:
++ DBG_log("kernel_netlink: auth truncation control should not reach here");
++ break;
++ }
++
+
+ strcpy(algo.alg_name, name);
+ memcpy(RTA_DATA(attr), &algo, sizeof(algo));
+diff --git a/programs/pluto/spdb_v2_struct.c b/programs/pluto/spdb_v2_struct.c
+index a744100..a723130 100644
+--- a/programs/pluto/spdb_v2_struct.c
++++ b/programs/pluto/spdb_v2_struct.c
+@@ -283,6 +283,10 @@ enum ikev2_trans_type_integ v1tov2_integ(int oakley)
+ return IKEv2_AUTH_HMAC_SHA1_96;
+ case OAKLEY_SHA2_256:
+ return IKEv2_AUTH_HMAC_SHA2_256_128;
++ case OAKLEY_SHA2_384:
++ return IKEv2_AUTH_HMAC_SHA2_384_192;
++ case OAKLEY_SHA2_512:
++ return IKEv2_AUTH_HMAC_SHA2_512_256;
+ default:
+ return IKEv2_AUTH_INVALID;
+ }
+@@ -297,6 +301,10 @@ enum ikev2_trans_type_integ v1phase2tov2child_integ(int ikev1_phase2_auth)
+ return IKEv2_AUTH_HMAC_SHA1_96;
+ case AUTH_ALGORITHM_HMAC_SHA2_256:
+ return IKEv2_AUTH_HMAC_SHA2_256_128;
++ case AUTH_ALGORITHM_HMAC_SHA2_384:
++ return IKEv2_AUTH_HMAC_SHA2_384_192;
++ case AUTH_ALGORITHM_HMAC_SHA2_512:
++ return IKEv2_AUTH_HMAC_SHA2_512_256;
+ default:
+ return IKEv2_AUTH_INVALID;
+ }
+@@ -312,6 +320,10 @@ static enum ikev2_trans_type_prf v1tov2_prf(int oakley)
+ return IKEv2_PRF_HMAC_SHA1;
+ case OAKLEY_SHA2_256:
+ return IKEv2_PRF_HMAC_SHA2_256;
++ case OAKLEY_SHA2_384:
++ return IKEv2_PRF_HMAC_SHA2_384;
++ case OAKLEY_SHA2_512:
++ return IKEv2_PRF_HMAC_SHA2_512;
+ default:
+ return IKEv2_PRF_INVALID;
+ }
diff --git a/openswan-ikev2.patch b/openswan-ikev2.patch
new file mode 100644
index 0000000..e060357
--- /dev/null
+++ b/openswan-ikev2.patch
@@ -0,0 +1,3116 @@
+From 3c685356d477d78a630f9f071fd0ceed6f53729a Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Tue, 7 Aug 2012 11:56:57 -0400
+Subject: IKEv2 RFC4306/5996 related changes
+
+
+diff --git a/include/pluto_constants.h b/include/pluto_constants.h
+index ffdee8f..b55c0a5 100644
+--- a/include/pluto_constants.h
++++ b/include/pluto_constants.h
+@@ -311,6 +311,13 @@ enum phase1_role {
+ RESPONDER=2
+ };
+
++enum ikev2_msgtype {
++ req_sent=1,
++ req_recd=2,
++ response_sent=3,
++ response_recd=4
++};
++
+
+ #define STATE_IKE_FLOOR STATE_MAIN_R0
+
+@@ -358,12 +365,12 @@ enum phase1_role {
+ #define IS_MODE_CFG_ESTABLISHED(s) ((s) == STATE_MODE_CFG_R2)
+ #endif
+
+-#define IS_PARENT_SA_ESTABLISHED(s) ((s) == STATE_PARENT_I2 || (s) == STATE_PARENT_R1 || (s) == STATE_IKESA_DEL)
++#define IS_PARENT_SA_ESTABLISHED(s) ((s) == STATE_PARENT_I3 || (s) == STATE_PARENT_R2)
+ /*
+ * Issue here is that our child sa appears as a STATE_PARENT_I3/STATE_PARENT_R2 state which it should not
+ * So we fall back to checking if it is cloned, and therefor really a child
+ */
+-#define IS_CHILD_SA_ESTABLISHED(st) ( (((st->st_state == STATE_PARENT_I3) || (st->st_state == STATE_PARENT_R2)) && (st->st_clonedfrom != SOS_NOBODY)) || (st->st_state == STATE_CHILDSA_DEL) )
++#define IS_CHILD_SA_ESTABLISHED(st) (((st->st_state) == STATE_PARENT_I3 || (st->st_state) == STATE_PARENT_R2 || (st->st_state) == STATE_CHILDSA_DEL) && (st->st_childsa != NULL))
+
+ #define IS_CHILD_SA(st) ((st)->st_clonedfrom != SOS_NOBODY)
+ #define IS_PARENT_SA(st) (!IS_CHILD_SA(st))
+diff --git a/lib/libopenswan/constants.c b/lib/libopenswan/constants.c
+index 9c85cf5..e970509 100644
+--- a/lib/libopenswan/constants.c
++++ b/lib/libopenswan/constants.c
+@@ -40,6 +40,21 @@ static const char *const version_name_1[] = {
+ };
+ static const char *const version_name_2[] = {
+ "IKEv2 version 2.0 (rfc4306/rfc5996)",
++ "IKEv2 version 2.0 (rfc4306/rfc5996)",
++ "IKEv2 version 2.0 (rfc4306/rfc5996)",
++ "IKEv2 version 2.0 (rfc4306/rfc5996)",
++ "IKEv2 version 2.0 (rfc4306/rfc5996)",
++ "IKEv2 version 2.0 (rfc4306/rfc5996)",
++ "IKEv2 version 2.0 (rfc4306/rfc5996)",
++ "IKEv2 version 2.0 (rfc4306/rfc5996)",
++ "IKEv2 version 2.0 (rfc4306/rfc5996)",
++ "IKEv2 version 2.0 (rfc4306/rfc5996)",
++ "IKEv2 version 2.0 (rfc4306/rfc5996)",
++ "IKEv2 version 2.0 (rfc4306/rfc5996)",
++ "IKEv2 version 2.0 (rfc4306/rfc5996)",
++ "IKEv2 version 2.0 (rfc4306/rfc5996)",
++ "IKEv2 version 2.0 (rfc4306/rfc5996)",
++ "IKEv2 version 2.0 (rfc4306/rfc5996)",
+ };
+
+ enum_names version_names_1 =
+@@ -47,9 +62,10 @@ enum_names version_names_1 =
+ ISAKMP_MAJOR_VERSION<<ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION,
+ version_name_1, NULL };
+
++/* To ignore or (in other words, accept) all IKEv2 minor versions*/
+ enum_names version_names =
+- { IKEv2_MAJOR_VERSION<<ISA_MAJ_SHIFT | IKEv2_MINOR_VERSION,
+- IKEv2_MAJOR_VERSION<<ISA_MAJ_SHIFT | IKEv2_MINOR_VERSION,
++ { IKEv2_MAJOR_VERSION<<ISA_MAJ_SHIFT | 0x0,
++ IKEv2_MAJOR_VERSION<<ISA_MAJ_SHIFT | 0xf,
+ version_name_2, &version_names_1 };
+
+ /* Domain of Interpretation */
+diff --git a/lib/libpluto/packet.c b/lib/libpluto/packet.c
+index ec4288b..bac754a 100644
+--- a/lib/libpluto/packet.c
++++ b/lib/libpluto/packet.c
+@@ -664,7 +664,7 @@ struct_desc ikev2_sa_desc = { "IKEv2 Security Association Payload",
+ */
+ static field_desc ikev2prop_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+- { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
++ { ft_nat, 8/BITS_PER_BYTE, "reserved", NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "prop #", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "proto ID", NULL },
+@@ -695,10 +695,10 @@ struct_desc ikev2_prop_desc = { "IKEv2 Proposal Substructure Payload",
+ */
+ static field_desc ikev2trans_fields[] = {
+ { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
+- { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
++ { ft_nat, 8/BITS_PER_BYTE, "reserved", NULL },
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "transform type", &trans_type_names },
+- { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
++ { ft_nat, 8/BITS_PER_BYTE, "reserved", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "transform ID", NULL },
+ { ft_end, 0, NULL, NULL }
+ };
+@@ -757,7 +757,7 @@ static field_desc ikev2ke_fields[] = {
+ { ft_set, 8/BITS_PER_BYTE, "critical bit", critical_names},
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_nat, 16/BITS_PER_BYTE, "transform type", &oakley_group_names },
+- { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
++ { ft_nat, 16/BITS_PER_BYTE, "reserved", NULL },
+ { ft_end, 0, NULL, NULL }
+ };
+
+@@ -800,8 +800,8 @@ static field_desc ikev2id_fields[] = {
+ { ft_set, 8/BITS_PER_BYTE, "critical bit", critical_names},
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "id_type", &ident_names },
+- { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+- { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
++ { ft_nat, 8/BITS_PER_BYTE, "reserved", NULL },
++ { ft_nat, 16/BITS_PER_BYTE, "reserved", NULL },
+ { ft_end, 0, NULL, NULL }
+ };
+
+@@ -883,8 +883,8 @@ static field_desc ikev2a_fields[] = {
+ { ft_set, 8/BITS_PER_BYTE, "critical bit", critical_names},
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_enum, 8/BITS_PER_BYTE, "auth method", &ikev2_auth_names },
+- { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+- { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
++ { ft_nat, 8/BITS_PER_BYTE, "reserved", NULL },
++ { ft_nat, 16/BITS_PER_BYTE, "reserved", NULL },
+ { ft_end, 0, NULL, NULL }
+ };
+
+@@ -948,6 +948,10 @@ static field_desc ikev2_notify_fields[] = {
+ { ft_end, 0, NULL, NULL }
+ };
+
++struct_desc ikev2_notify_desc = { "IKEv2 Notify Payload",
++ ikev2_notify_fields, sizeof(struct ikev2_notify) };
++
++
+ /* IKEv2 Delete Payload
+ * layout from RFC 5996 Section 3.11
+ * This is followed by a variable length SPI.
+@@ -978,10 +982,6 @@ static field_desc ikev2_delete_fields[] = {
+ struct_desc ikev2_delete_desc = { "IKEv2 Delete Payload",
+ ikev2_delete_fields, sizeof(struct ikev2_delete) };
+
+-
+-struct_desc ikev2_notify_desc = { "IKEv2 Notify Payload",
+- ikev2_notify_fields, sizeof(struct ikev2_notify) };
+-
+ /*
+ * 3.12. Vendor ID Payload
+ *
+@@ -1029,11 +1029,11 @@ static field_desc ikev2ts_fields[] = {
+ { ft_set, 8/BITS_PER_BYTE, "critical bit", critical_names},
+ { ft_len, 16/BITS_PER_BYTE, "length", NULL },
+ { ft_nat, 8/BITS_PER_BYTE, "number of TS", NULL},
+- { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
+- { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
++ { ft_nat, 8/BITS_PER_BYTE, "reserved", NULL },
++ { ft_nat, 16/BITS_PER_BYTE, "reserved", NULL },
+ { ft_end, 0, NULL, NULL }
+ };
+-struct_desc ikev2_ts_desc = { "IKEv2 Traffic Selector Payload",
++struct_desc ikev2_ts_desc = { "IKEv2 Traffic Selectors",
+ ikev2ts_fields, sizeof(struct ikev2_ts) };
+
+
+@@ -1066,7 +1066,7 @@ static field_desc ikev2ts1_fields[] = {
+ { ft_nat, 16/BITS_PER_BYTE, "end port", NULL},
+ { ft_end, 0, NULL, NULL }
+ };
+-struct_desc ikev2_ts1_desc = { "IKEv2 Traffic Selector",
++struct_desc ikev2_ts1_desc = { "IKEv2 Traffic Selectors",
+ ikev2ts1_fields, sizeof(struct ikev2_ts1) };
+
+
+diff --git a/lib/libpluto/pluto_constants.c b/lib/libpluto/pluto_constants.c
+index 0a51292..a66dfd9 100644
+--- a/lib/libpluto/pluto_constants.c
++++ b/lib/libpluto/pluto_constants.c
+@@ -139,6 +139,8 @@ static const char *const state_name[] = {
+ "STATE_PARENT_I3",
+ "STATE_PARENT_R1",
+ "STATE_PARENT_R2",
++ "STATE_IKESA_DEL",
++ "STATE_CHILDSA_DEL",
+ "STATE_IKEv2_ROOF"
+
+ };
+@@ -191,6 +193,8 @@ const char *const state_story[] = {
+ "PARENT SA established",
+ "received v2I1, sent v2R1",
+ "received v2I2, PARENT SA established",
++ "sent IKE SA delete request",
++ "sent Child SA delete request",
+ "invalid state - IKEv2 roof"
+ };
+
+diff --git a/programs/pluto/connections.c b/programs/pluto/connections.c
+index eb2b492..6086840 100644
+--- a/programs/pluto/connections.c
++++ b/programs/pluto/connections.c
+@@ -1683,6 +1683,65 @@ instantiate(struct connection *c, const ip_address *him
+ }
+
+ struct connection *
++ikev2_narrow_instantiate(struct connection *c)
++{
++ struct connection *d;
++ int wildcards;
++
++ /*if(!(c->policy & POLICY_IKEV2_ALLOW) && !(c->policy & POLICY_IKEV2_PROPOSE)) {
++ passert(c->kind == CK_TEMPLATE);
++ }
++
++ passert(c->spd.next == NULL);*/
++
++ c->instance_serial++;
++ d = clone_thing(*c, "temporary connection");
++
++ /*if (his_id != NULL)
++ {
++ passert(match_id(his_id, &d->spd.that.id, &wildcards));
++ d->spd.that.id = *his_id;
++ d->spd.that.has_id_wildcards = FALSE;
++ }*/
++
++ unshare_connection_strings(d);
++ unshare_ietfAttrList(&d->spd.this.groups);
++ unshare_ietfAttrList(&d->spd.that.groups);
++
++ d->kind = CK_INSTANCE;
++
++ passert(oriented(*d));
++ /*d->spd.that.host_addr = *him;
++ setportof(htons(c->spd.that.port), &d->spd.that.host_addr);
++ default_end(&d->spd.that, &d->spd.this.host_addr);*/
++
++ /* We cannot guess what our next_hop should be, but if it was
++ * explicitly specified as 0.0.0.0, we set it to be him.
++ * (whack will not allow nexthop to be elided in RW case.)
++ */
++ /*default_end(&d->spd.this, &d->spd.that.host_addr);*/
++ d->spd.next = NULL;
++ d->spd.reqid = gen_reqid();
++
++ /* set internal fields */
++ d->ac_next = connections;
++ connections = d;
++ d->spd.routing = RT_UNROUTED;
++ d->newest_isakmp_sa = SOS_NOBODY;
++ d->newest_ipsec_sa = SOS_NOBODY;
++ d->spd.eroute_owner = SOS_NOBODY;
++
++ /* reset log file info */
++ d->log_file_name = NULL;
++ d->log_file = NULL;
++ d->log_file_err = FALSE;
++
++ connect_to_host_pair(d);
++
++ return d;
++}
++
++struct connection *
+ rw_instantiate(struct connection *c
+ , const ip_address *him
+ , const ip_subnet *his_net
+diff --git a/programs/pluto/connections.h b/programs/pluto/connections.h
+index 36f8517..9bbd145 100644
+--- a/programs/pluto/connections.h
++++ b/programs/pluto/connections.h
+@@ -374,6 +374,7 @@ find_connection_for_clients(struct spd_route **srp
+ */
+ struct gw_info; /* forward declaration of tag (defined in dnskey.h) */
+ struct alg_info; /* forward declaration of tag (defined in alg_info.h) */
++extern struct connection *ikev2_narrow_instantiate(struct connection *c);
+ extern struct connection *rw_instantiate(struct connection *c
+ , const ip_address *him
+ , const ip_subnet *his_net
+diff --git a/programs/pluto/hmac.c b/programs/pluto/hmac.c
+index 7d201db..1f129f7 100644
+--- a/programs/pluto/hmac.c
++++ b/programs/pluto/hmac.c
+@@ -158,13 +158,9 @@ hmac_update(struct hmac_ctx *ctx,
+ const u_char *data, size_t data_len)
+ {
+ #ifdef HAVE_LIBNSS
+- DBG(DBG_CRYPT, DBG_dump("hmac_update data value: ", data, data_len));
+ if(data_len > 0) {
+- DBG(DBG_CRYPT, DBG_log("hmac_update: inside if"));
+ SECStatus status = PK11_DigestOp(ctx->ctx_nss, data, data_len);
+- DBG(DBG_CRYPT, DBG_log("hmac_update: after digest"));
+ PR_ASSERT(status == SECSuccess);
+- DBG(DBG_CRYPT, DBG_log("hmac_update: after assert"));
+ }
+ #else
+ ctx->h->hash_update(&ctx->hash_ctx, data, data_len);
+diff --git a/programs/pluto/ikev2.c b/programs/pluto/ikev2.c
+index 260e3b5..fc42628 100644
+--- a/programs/pluto/ikev2.c
++++ b/programs/pluto/ikev2.c
+@@ -247,7 +247,6 @@ ikev2_process_payloads(struct msg_digest *md,
+ int thisp = np;
+ bool unknown_payload = FALSE;
+
+- DBG(DBG_CONTROL, DBG_log("Now lets proceed with payload (%s)",enum_show(&payload_names, thisp)));
+ memset(pd, 0, sizeof(*pd));
+
+ if (pd == &md->digest[PAYLIMIT])
+@@ -315,7 +314,6 @@ ikev2_process_payloads(struct msg_digest *md,
+ pd++;
+ }
+
+- DBG(DBG_CONTROL, DBG_log("Finished and now at the end of ikev2_process_payload"));
+ md->digest_roof = pd;
+ return STF_OK;
+ }
+@@ -349,7 +347,7 @@ process_v2_packet(struct msg_digest **mdp)
+
+ md->role = RESPONDER;
+
+- DBG(DBG_CONTROL, DBG_log("I am IKE SA Responder"));
++ DBG(DBG_CONTROLMORE, DBG_log("I am IKE SA Responder"));
+
+ st = find_state_ikev2_parent(md->hdr.isa_icookie
+ , md->hdr.isa_rcookie);
+@@ -360,22 +358,35 @@ process_v2_packet(struct msg_digest **mdp)
+ }
+
+ if(st) {
+- if(st->st_msgid_lastrecv > md->msgid_received){
++ /* if it is request from Initiator*/
++ if(!(md->hdr.isa_flags & ISAKMP_FLAGS_R)) {
++ if(st->st_msgid_last_remotereq != INVALID_MSGID && st->st_msgid_last_remotereq > md->msgid_received){
+ /* this is an OLD retransmit. we can't do anything */
+- openswan_log("received too old retransmit: %u < %u"
+- , md->msgid_received, st->st_msgid_lastrecv);
++ openswan_log("received too old retransmit, ignoring: %u < %u"
++ , md->msgid_received, st->st_msgid_last_remotereq);
+ return;
+- }
+- if(st->st_msgid_lastrecv == md->msgid_received){
++ }
++ if(st->st_msgid_last_remotereq != INVALID_MSGID && st->st_msgid_last_remotereq == md->msgid_received){
+ /* this is a recent retransmit. */
+ send_packet(st, "ikev2-responder-retransmit", FALSE);
+ return;
++ }
++ }
++ else
++ {
++ /* if it is response from Initiator*/
++ /* it seems that it should not happen
++ * why a response will be retransmitted?
++ */
++ if(st->st_msgid_last_localreq_ack!=INVALID_MSGID && st->st_msgid_last_localreq_ack >= md->msgid_received){
++ openswan_log("received an old response, ignoring: %u < %u"
++ , md->msgid_received, st->st_msgid_last_localreq_ack);
++ }
+ }
+ /* update lastrecv later on */
+ }
+-
+ } else {
+- /* then I am the initiator, and this is a reply */
++ /* then I am the initiator, and this may be a reply or request */
+
+ md->role = INITIATOR;
+
+@@ -412,26 +423,31 @@ process_v2_packet(struct msg_digest **mdp)
+ }
+
+ if(st) {
+- /*
+- * then there is something wrong with the msgid, so
+- * maybe they retransmitted for some reason.
+- * Check if it's an old packet being returned, and
+- * if so, drop it.
+- * NOTE: in_struct() changed the byte order.
+- */
+- if(st->st_msgid_lastack != INVALID_MSGID
+- && md->msgid_received <= st->st_msgid_lastack) {
+- /* it's fine, it's just a retransmit */
+- DBG(DBG_CONTROL, DBG_log("responding peer retransmitted msgid %u"
+- , md->msgid_received));
++ /* if it is request from Responder*/
++ if(!(md->hdr.isa_flags & ISAKMP_FLAGS_R)) {
++ if(st->st_msgid_last_remotereq != INVALID_MSGID && st->st_msgid_last_remotereq > md->msgid_received){
++ /* this is an OLD retransmit. we can't do anything */
++ openswan_log("received too old retransmit, ignoring: %u < %u"
++ , md->msgid_received, st->st_msgid_last_remotereq);
++ return;
++ }
++ if(st->st_msgid_last_remotereq != INVALID_MSGID && st->st_msgid_last_remotereq == md->msgid_received){
++ /* this is a recent retransmit. */
++ send_packet(st, "ikev2-responder-retransmit", FALSE);
+ return;
++ }
++ }
++ else
++ {
++ /* if it is response from Responder*/
++ /* it seems that it should not happen
++ * why a response will be retransmitted?
++ */
++ if(st->st_msgid_last_localreq_ack!=INVALID_MSGID && st->st_msgid_last_localreq_ack >= md->msgid_received){
++ openswan_log("received an old response, ignoring: %u < %u"
++ , md->msgid_received, st->st_msgid_last_localreq_ack);
++ }
+ }
+-#if 0
+- openswan_log("last msgid ack is %u, received: %u"
+- , st->st_msgid_lastack
+- , md->msgid_received);
+- return;
+-#endif
+ }
+ }
+
+@@ -439,7 +455,6 @@ process_v2_packet(struct msg_digest **mdp)
+ if(st) {
+
+ from_state = st->st_state;
+- DBG(DBG_CONTROL, DBG_log("state found and its state is (%s)", enum_show(&state_names, from_state)));
+ }
+
+ for(svm = state_microcode_table; svm->state != STATE_IKEv2_ROOF; svm++) {
+@@ -451,20 +466,12 @@ process_v2_packet(struct msg_digest **mdp)
+ }
+ if(svm->state != from_state) continue;
+ if(svm->recv_type != ix) continue;
+-
+- /* I1 receiving NO_PROPOSAL ened 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;
+
+ /* must be the right state */
+ break;
+ }
+
+ if(svm->state == STATE_IKEv2_ROOF) {
+- DBG(DBG_CONTROL, DBG_log("ended up with STATE_IKEv2_ROOF"));
+
+ /* no useful state */
+ if(md->hdr.isa_flags & ISAKMP_FLAGS_I) {
+@@ -480,7 +487,6 @@ process_v2_packet(struct msg_digest **mdp)
+ stf_status stf;
+ stf = ikev2_process_payloads(md, &md->message_pbs
+ , from_state, md->hdr.isa_np);
+- DBG(DBG_CONTROL, DBG_log("Finished processing ikev2_process_payloads"));
+
+ if(stf != STF_OK) {
+ complete_v2_state_transition(mdp, stf);
+@@ -488,7 +494,6 @@ 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)));
+@@ -667,7 +672,7 @@ send_v2_notification_from_md(struct msg_digest *md UNUSED, u_int16_t type
+ md->hdr.isa_icookie, md->hdr.isa_rcookie, data);
+ }
+
+-void ikev2_update_counters(struct msg_digest *md)
++void ikev2_update_counters(struct msg_digest *md, enum ikev2_msgtype msgtype)
+ {
+ struct state *pst= md->pst;
+ struct state *st = md->st;
+@@ -679,17 +684,21 @@ void ikev2_update_counters(struct msg_digest *md)
+ if(pst == NULL) pst = st;
+ }
+
+- switch(md->role) {
+- case INITIATOR:
+- /* update lastuse values */
+- pst->st_msgid_lastack = md->msgid_received;
+- pst->st_msgid_nextuse = pst->st_msgid_lastack+1;
+- break;
+-
+- case RESPONDER:
+- pst->st_msgid_lastrecv= md->msgid_received;
+- break;
+- }
++
++ switch(msgtype) {
++ case req_sent:
++ pst->st_msgid_last_localreq = pst->st_msgid_last_localreq == INVALID_MSGID? 0 : pst->st_msgid_last_localreq + 1;
++ break;
++ case req_recd:
++ break;
++ case response_sent:
++ pst->st_msgid_last_remotereq = md->msgid_received;
++ break;
++ case response_recd:
++ pst->st_msgid_last_localreq_ack = md->msgid_received;
++ break;
++ default: break;
++ }
+ }
+
+ static void success_v2_state_transition(struct msg_digest **mdp)
+@@ -707,8 +716,6 @@ static void success_v2_state_transition(struct msg_digest **mdp)
+ change_state(st, svm->next_state);
+ w = RC_NEW_STATE + st->st_state;
+
+- ikev2_update_counters(md);
+-
+
+ /* tell whack and log of progress */
+ {
+@@ -740,8 +747,8 @@ static void success_v2_state_transition(struct msg_digest **mdp)
+ } else if(IS_PARENT_SA_ESTABLISHED(st->st_state)) {
+ fmt_isakmp_sa_established(st, sadetails,sizeof(sadetails));
+ }
+-
+- if (IS_CHILD_SA_ESTABLISHED(st))
++
++ if (IS_CHILD_SA_ESTABLISHED(st) || IS_PARENT_SA_ESTABLISHED(st->st_state))
+ {
+ /* log our success */
+ w = RC_SUCCESS;
+@@ -901,26 +908,37 @@ void complete_v2_state_transition(struct msg_digest **mdp
+ struct msg_digest *md = *mdp;
+ /* const struct state_v2_microcode *svm=md->svm; */
+ struct state *st;
+- enum state_kind from_state = STATE_UNDEFINED;
++ enum state_kind from_state;
+ const char *from_state_name;
+
+- cur_state = st = md->st; /* might have changed */
++ /* advance the state */
++ DBG(DBG_CONTROL
++ , DBG_log("complete v2 state transition with %s"
++ , enum_name(&stfstatus_name, result)));
++
++ /* this occur when IKE SA state is deleted already */
++ if(md->st == NULL) {
++ goto end;
++ }
+
+- passert(st); /* apparently on STF_TOOMUCH_CRYPTO we have no state? Needs fixing */
++ cur_state = st = md->st; /* might have changed */
+
+ md->result = result;
+ TCLCALLOUT("v2AdjustFailure", st, (st ? st->st_connection : NULL), md);
+ result = md->result;
+
+- /* advance the state */
+- DBG(DBG_CONTROL
+- , DBG_log("complete v2 state transition with %s"
+- , enum_name(&stfstatus_name, (result > STF_FAIL) ? STF_FAIL : result)));
+
+ switch(result) {
+ case STF_IGNORE:
+ break;
+
++ case STF_INLINE: /* this is second time through complete
++ * state transition, so the MD has already
++ * been freed.
++ 0 */
++ *mdp = NULL;
++ break;
++
+ case STF_SUSPEND:
+ /* update the previous packet history */
+ /* IKEv2 XXX */ /* update_retransmit_history(st, md); */
+@@ -929,13 +947,6 @@ void complete_v2_state_transition(struct msg_digest **mdp
+ *mdp = NULL;
+ break;
+
+- case STF_INLINE: /* mcr: this is second time through complete
+- * state transition, so the MD has already
+- * been freed.
+- 0 */
+- *mdp = NULL;
+- /* fall through to STF_OK */
+-
+ case STF_OK:
+ /* advance the state */
+ success_v2_state_transition(mdp);
+@@ -994,18 +1005,21 @@ void complete_v2_state_transition(struct msg_digest **mdp
+ , from_state_name
+ , enum_name(&ipsec_notification_names, md->note));
+
++#if 0
+ if(md->note > 0) {
+ /* only send a notify is this packet was a question, not if it was an answer */
+ if(!(md->hdr.isa_flags & ISAKMP_FLAGS_R)) {
+ SEND_NOTIFICATION(md->note);
+ }
+ }
++#endif
+
+ DBG(DBG_CONTROL,
+ DBG_log("state transition function for %s failed: %s"
+ , from_state_name
+ , (md->note) ? enum_name(&ipsec_notification_names, md->note) : "<no reason given>" ));
+ }
++end:;
+ }
+
+ v2_notification_t
+diff --git a/programs/pluto/ikev2.h b/programs/pluto/ikev2.h
+index 8715114..c60e9b5 100644
+--- a/programs/pluto/ikev2.h
++++ b/programs/pluto/ikev2.h
+@@ -119,39 +119,44 @@ extern stf_status ikev2_verify_psk_auth(struct state *st
+ , unsigned char *idhash
+ , pb_stream *sig_pbs);
+
++extern int ikev2_parse_ts(struct payload_digest *const ts_pd
++ , struct traffic_selector *array
++ , unsigned int array_max);
++
+ extern stf_status ikev2_emit_ipsec_sa(struct msg_digest *md
+ , pb_stream *outpbs
+ , unsigned int np
+ , struct connection *c
+ , lset_t policy);
+
++extern struct connection *ikev2_create_narrowed_con(struct connection *c
++ , struct traffic_selector *narrowed_tsi
++ , struct traffic_selector *narrowed_tsr
++ , enum phase1_role role);
++
+ extern void ikev2_derive_child_keys(struct state *st
+ , enum phase1_role role);
+
+-extern struct traffic_selector ikev2_end_to_ts(struct end *e);
+-extern int ikev2_evaluate_connection_fit(struct connection *d
+- , struct spd_route *sr
+- , enum phase1_role role
+- , struct traffic_selector *tsi
+- , struct traffic_selector *tsr
+- , unsigned int tsi_n
+- , unsigned int tsr_n);
+-
+-extern int ikev2_evaluate_connection_port_fit(struct connection *d
+- , struct spd_route *sr
+- , enum phase1_role role
+- , struct traffic_selector *tsi
+- , struct traffic_selector *tsr
+- , unsigned int tsi_n
+- , unsigned int tsr_n
+- , unsigned int *best_tsi_i
+- , unsigned int *best_tsr_i);
++extern bool
++ikev2_perfect_match_ts(struct traffic_selector *tsi
++ ,struct traffic_selector *tsr
++ , unsigned int tsi_n
++ , unsigned int tsr_n
++ , struct connection *c
++ , enum phase1_role role);
+
+ extern stf_status ikev2_emit_ts(struct msg_digest *md
+ , pb_stream *outpbs
+ , unsigned int np
+ , struct traffic_selector *ts
+ , enum phase1_role role);
++extern void
++ikev2_store_ts_instate(struct traffic_selector *array_tsi
++ ,struct traffic_selector * array_tsr
++ , unsigned int tsi_n
++ , unsigned int tsr_n
++ , struct traffic_selector *ts_this
++ , struct traffic_selector *ts_that);
+
+ extern stf_status ikev2_calc_emit_ts(struct msg_digest *md
+ , pb_stream *outpbs
+@@ -159,18 +164,20 @@ extern stf_status ikev2_calc_emit_ts(struct msg_digest *md
+ , struct connection *c0
+ , lset_t policy);
+
+-extern int ikev2_parse_ts(struct payload_digest *ts_pd
+- , struct traffic_selector *array
+- , unsigned int array_max);
++extern bool ikev2_verify_ts(struct traffic_selector *tsi
++ , struct traffic_selector *tsr
++ , unsigned int tsi_n
++ , unsigned int tsr_n
++ , struct traffic_selector *this_ts
++ , struct traffic_selector *that_ts
++ , enum phase1_role role);
+
+ extern stf_status ikev2_child_sa_respond(struct msg_digest *md
+ , enum phase1_role role
+ , pb_stream *outpbs);
+
+-extern struct traffic_selector ikev2_end_to_ts(struct end *e);
+-extern void ikev2_update_counters(struct msg_digest *md);
+-extern void ikev2_print_ts(struct traffic_selector *ts);
+-
++extern struct traffic_selector ikev2_subnettots(struct end *e);
++extern void ikev2_update_counters(struct msg_digest *md, enum ikev2_msgtype msgtype);
+
+ extern void send_v2_notification(struct state *p1st, u_int16_t type
+ , struct state *encst
+diff --git a/programs/pluto/ikev2_child.c b/programs/pluto/ikev2_child.c
+index af194f2..764ca3a 100644
+--- a/programs/pluto/ikev2_child.c
++++ b/programs/pluto/ikev2_child.c
+@@ -64,40 +64,8 @@
+ #include "virtual.h"
+ #include "hostpair.h"
+
+-static void print_ikev2_ts(struct traffic_selector *ts){
+- char lbx[ADDRTOT_BUF];
+- char hbx[ADDRTOT_BUF];
+-
+- DBG_log("PAUL marker ------------------------");
+- DBG_log("ts_type: %s", enum_name(&ikev2_ts_type_names, ts->ts_type));
+- DBG_log("ipprotoid: %d", ts->ipprotoid);
+- DBG_log("startport: %d", ts->startport);
+- DBG_log("endport: %d", ts->endport);
+- addrtot(&ts->low, 0, lbx, sizeof(lbx));
+- addrtot(&ts->high, 0, hbx, sizeof(hbx));
+- DBG_log("ip low: %s", lbx);
+- DBG_log("ip high: %s", hbx);
+- DBG_log("PAUL marker ------------------------");
+-}
+-
+-void ikev2_print_ts(struct traffic_selector *ts){
+- char lbx[ADDRTOT_BUF];
+- char hbx[ADDRTOT_BUF];
+-
+- DBG_log("printing contents struct traffic_selector");
+- DBG_log(" ts_type: %s", enum_name(&ikev2_ts_type_names, ts->ts_type));
+- DBG_log(" ipprotoid: %d", ts->ipprotoid);
+- DBG_log(" startport: %d", ts->startport);
+- DBG_log(" endport: %d", ts->endport);
+- addrtot(&ts->low, 0, lbx, sizeof(lbx));
+- addrtot(&ts->high, 0, hbx, sizeof(hbx));
+- DBG_log(" ip low: %s", lbx);
+- DBG_log(" ip high: %s", hbx);
+-}
+-
+-
+ /* rewrite me with addrbytesptr() */
+-struct traffic_selector ikev2_end_to_ts(struct end *e)
++struct traffic_selector ikev2_subnettots(struct end *e)
+ {
+ struct traffic_selector ts;
+ struct in6_addr v6mask;
+@@ -129,9 +97,25 @@ struct traffic_selector ikev2_end_to_ts(struct end *e)
+ ts.high.u.v6.sin6_addr.s6_addr32[2]|= ~v6mask.s6_addr32[2];
+ ts.high.u.v6.sin6_addr.s6_addr32[3]|= ~v6mask.s6_addr32[3];
+ break;
++ }
+
+ /* Setting ts_type IKEv2_TS_FC_ADDR_RANGE (RFC-4595) not yet supproted */
+- }
++
++ /*
++ * The IKEv2 code used to send 0-65535 as port regardless of
++ * the local policy specified. if local policy states a specific
++ * protocol and port, then send that protocol value and port to
++ * other end -- Avesh
++ * Paul: TODO: I believe IKEv2 allows multiple port ranges?
++ */
++
++ DBG(DBG_CONTROLMORE,
++ {
++ DBG_log("local policy host_addr-port=%d, client-port=%d, port=%d, protocol=%d, has_port_wildcard=%d",
++ ntohs(e->host_addr.u.v4.sin_port), ntohs(e->client.addr.u.v4.sin_port)
++ , e->port, e->protocol, e->has_port_wildcard);
++ }
++ );
+
+ ts.ipprotoid = e->protocol;
+
+@@ -148,9 +132,60 @@ struct traffic_selector ikev2_end_to_ts(struct end *e)
+ ts.endport = e->port;
+ }
+
++ ts.next = NULL;
++
+ return ts;
+ }
+
++void
++ikev2_store_ts_instate(struct traffic_selector *array_tsi
++ ,struct traffic_selector * array_tsr
++ , unsigned int tsi_n
++ , unsigned int tsr_n
++ , struct traffic_selector *ts_this
++ , struct traffic_selector *ts_that)
++{
++ unsigned int i;
++ struct traffic_selector *curts, *prevts;
++
++ prevts = NULL;
++ curts = ts_this;
++ for(i=0; i<tsi_n; i++) {
++ if(curts == NULL) {
++ curts = alloc_thing(struct traffic_selector, "struct traffic_selector");
++ }
++
++ *curts = array_tsi[i];
++ curts->next = NULL;
++
++ if(prevts!= NULL) {
++ prevts->next = curts;
++ }
++
++ prevts = curts;
++ curts = curts->next;
++ }
++
++ prevts = NULL;
++ curts = ts_that;
++
++ for(i=0; i<tsr_n; i++) {
++ if(curts == NULL) {
++ curts = alloc_thing(struct traffic_selector, "struct traffic_selector");
++ }
++
++ *curts = array_tsr[i];
++ curts->next = NULL;
++
++ if(prevts!= NULL) {
++ prevts->next = curts;
++ }
++
++ prevts = curts;
++ curts = curts->next;
++ }
++}
++
+ stf_status ikev2_emit_ts(struct msg_digest *md UNUSED
+ , pb_stream *outpbs
+ , unsigned int np
+@@ -161,22 +196,30 @@ stf_status ikev2_emit_ts(struct msg_digest *md UNUSED
+ struct ikev2_ts1 its1;
+ pb_stream ts_pbs;
+ pb_stream ts_pbs2;
++ struct traffic_selector *tmp=ts;
+
+ its.isat_np = np;
+ its.isat_critical = ISAKMP_PAYLOAD_NONCRITICAL;
+- its.isat_num = 1;
++
++ its.isat_num = 0;
++ while(tmp!=NULL) {
++ its.isat_num++;
++ tmp = tmp->next;
++ }
+
+ if(!out_struct(&its, &ikev2_ts_desc, outpbs, &ts_pbs))
+ return STF_INTERNAL_ERROR;
+
++ while(ts!=NULL) {
++
+ switch(ts->ts_type) {
+ case IKEv2_TS_IPV4_ADDR_RANGE:
+ its1.isat1_type = IKEv2_TS_IPV4_ADDR_RANGE;
+- its1.isat1_sellen = 2*4 + 8; /* See RFC 5669 SEction 13.3.1, 8 octet header plus 2 ip addresses */
++ its1.isat1_sellen = 16;
+ break;
+ case IKEv2_TS_IPV6_ADDR_RANGE:
+ its1.isat1_type = IKEv2_TS_IPV6_ADDR_RANGE;
+- its1.isat1_sellen = 2*16 + 8; /* See RFC 5669 SEction 13.3.1, 8 octet header plus 2 ip addresses */
++ its1.isat1_sellen = 40;
+ break;
+ case IKEv2_TS_FC_ADDR_RANGE:
+ DBG_log("IKEv2 Traffic Selector IKEv2_TS_FC_ADDR_RANGE not yet supported");
+@@ -185,6 +228,14 @@ stf_status ikev2_emit_ts(struct msg_digest *md UNUSED
+ DBG_log("IKEv2 Traffic Selector type '%d' not supported", ts->ts_type);
+ }
+
++ /*
++ * The IKEv2 code used to send 0-65535 as port regardless of
++ * the local policy specified. if local policy states a specific
++ * protocol and port, then send that protocol value and port to
++ * other end -- Avesh
++ * Paul: TODO: I believe IKEv2 allows multiple port ranges?
++ */
++
+ its1.isat1_ipprotoid = ts->ipprotoid; /* protocol as per local policy*/
+ its1.isat1_startport = ts->startport; /* ports as per local policy*/
+ its1.isat1_endport = ts->endport;
+@@ -212,11 +263,56 @@ stf_status ikev2_emit_ts(struct msg_digest *md UNUSED
+ }
+
+ close_output_pbs(&ts_pbs2);
++ ts = ts->next;
++ }
++
+ close_output_pbs(&ts_pbs);
+
+ return STF_OK;
+ }
+
++bool
++ikev2_perfect_match_ts(struct traffic_selector *tsi
++ ,struct traffic_selector *tsr
++ , unsigned int tsi_n
++ , unsigned int tsr_n
++ , struct connection *c
++ , enum phase1_role role)
++{
++ struct end *ei, *er;
++ struct traffic_selector tmpi, tmpr;
++
++ if(tsi_n > 1 || tsi_n > 1) {
++ return FALSE;
++ }
++
++ if(role == INITIATOR) {
++ ei = &c->spd.this;
++ er = &c->spd.that;
++ } else {
++ ei = &c->spd.that;
++ er = &c->spd.this;
++ }
++
++ tmpi = ikev2_subnettots(ei);
++ tmpr = ikev2_subnettots(er);
++
++ if(addrcmp(&tmpi.low, &tsi[0].low) == 0
++ && addrcmp(&tmpi.high, &tsi[0].high) == 0
++ && tmpi.startport == tsi[0].startport
++ && tmpi.endport == tsi[0].endport
++ && tmpi.ipprotoid == tsi[0].ipprotoid
++ && addrcmp(&tmpr.low, &tsr[0].low) == 0
++ && addrcmp(&tmpr.high, &tsr[0].high) == 0
++ && tmpr.startport == tsr[0].startport
++ && tmpr.endport == tsr[0].endport
++ && tmpr.ipprotoid == tsr[0].ipprotoid)
++ {
++ return TRUE;
++ }
++
++ return FALSE;
++}
+
+ stf_status ikev2_calc_emit_ts(struct msg_digest *md
+ , pb_stream *outpbs
+@@ -226,10 +322,8 @@ stf_status ikev2_calc_emit_ts(struct msg_digest *md
+ {
+ struct state *st = md->st;
+ struct traffic_selector *ts_i, *ts_r;
+- struct spd_route *sr;
+ stf_status ret;
+
+- st->st_childsa = c0;
+
+ if(role == INITIATOR) {
+ ts_i = &st->st_ts_this;
+@@ -239,7 +333,6 @@ stf_status ikev2_calc_emit_ts(struct msg_digest *md
+ ts_r = &st->st_ts_this;
+ }
+
+- for(sr=&c0->spd; sr != NULL; sr = sr->next) {
+ ret = ikev2_emit_ts(md, outpbs, ISAKMP_NEXT_v2TSr
+ , ts_i, INITIATOR);
+ if(ret!=STF_OK) return ret;
+@@ -266,11 +359,83 @@ stf_status ikev2_calc_emit_ts(struct msg_digest *md
+ }
+
+ if(ret!=STF_OK) return ret;
+- }
+
+ return STF_OK;
+ }
+
++bool
++ikev2_verify_ts(struct traffic_selector *tsi
++ , struct traffic_selector *tsr
++ , unsigned int ntsi
++ , unsigned int ntsr
++ , struct traffic_selector *this_ts
++ , struct traffic_selector *that_ts
++ , enum phase1_role role)
++{
++ unsigned int i;
++ struct traffic_selector *tmptsi, *tmptsr;
++
++
++ if(role == INITIATOR) {
++ tmptsi = this_ts;
++ tmptsr = that_ts;
++ }
++ else {
++ tmptsi = that_ts;
++ tmptsr = this_ts;
++ }
++
++ for(i = 0; i < ntsi; i++ ) {
++
++ /* verify addresses*/
++ if(addrcmp(&tmptsi->low, &tsi[i].low) > 0
++ || addrcmp(&tmptsi->high, &tsi[i].high) < 0)
++ {
++ return FALSE;
++ }
++
++ /* verify port */
++ if(tmptsi->startport > tsi[i].startport
++ || tmptsi->endport < tsi[i].endport)
++ {
++ return FALSE;
++ }
++
++ /* verify protocol */
++ if( tmptsi->ipprotoid !=0
++ && tmptsi->ipprotoid != tsi[i].ipprotoid)
++ {
++ return FALSE;
++ }
++ }
++
++ for(i = 0; i < ntsr; i++ ) {
++
++ /* verify addresses*/
++ if(addrcmp(&tmptsr->low, &tsr[i].low) > 0
++ || addrcmp(&tmptsr->high, &tsr[i].high) < 0)
++ {
++ return FALSE;
++ }
++
++ /* verify port */
++ if(tmptsr->startport > tsr[i].startport
++ || tmptsr->endport < tsr[i].endport)
++ {
++ return FALSE;
++ }
++
++ /* verify protocol */
++
++ if( tmptsr->ipprotoid !=0
++ && tmptsr->ipprotoid != tsr[i].ipprotoid)
++ {
++ return FALSE;
++ }
++ }
++ return TRUE;
++}
++
+ /* return number of traffic selectors found */
+ int
+ ikev2_parse_ts(struct payload_digest *const ts_pd
+@@ -339,271 +504,675 @@ ikev2_parse_ts(struct payload_digest *const ts_pd
+ return i;
+ }
+
+-int ikev2_evaluate_connection_port_fit(struct connection *d
+- , struct spd_route *sr
+- , enum phase1_role role
+- , struct traffic_selector *tsi
+- , struct traffic_selector *tsr
+- , unsigned int tsi_n
+- , unsigned int tsr_n
+- , unsigned int *best_tsi_i
+- , unsigned int *best_tsr_i)
++static bool
++ikev2_narrowing(struct connection *c
++ , enum phase1_role role
++ , struct traffic_selector *tsi
++ , struct traffic_selector *tsr
++ , unsigned int tsi_n
++ , unsigned int tsr_n
++ , struct traffic_selector **narrowed_tsi
++ , struct traffic_selector **narrowed_tsr
++ , struct connection **result)
+ {
+- unsigned int tsi_ni, tsr_ni;
+- int bestfit_p = -1;
+- struct end *ei, *er;
+- int narrowing = (d->policy & POLICY_IKEV2_ALLOW_NARROWING);
++struct host_pair *hp = NULL;
++struct connection *d;
++unsigned int i;
++struct end *ei, *er;
++int bests=0;
++struct connection *bestc=NULL;
++bool specific_first_ts = FALSE;
+
+- if(role == INITIATOR) {
+- ei = &sr->this;
+- er = &sr->that;
+- } else {
+- ei = &sr->that;
+- er = &sr->this;
+- }
+- /* compare tsi/r array to this/that, evaluating port ranges how well it fits */
+- for(tsi_ni = 0; tsi_ni < tsi_n; tsi_ni++) {
+- for(tsr_ni=0; tsr_ni<tsr_n; tsr_ni++) {
+- int fitrange1 = 0;
+- int fitrange2 = 0;
+-
+- DBG(DBG_CONTROL,DBG_log("ei->port %d tsi[tsi_ni].startport %d tsi[tsi_ni].endport %d narrowing=%s"
+- ,ei->port , tsi[tsi_ni].startport, tsi[tsi_ni].endport, (narrowing ? "yes" : "no")));
+-
+- if((ei->port) && (( ei->port == tsi[tsi_ni].startport ) && (ei->port == tsi[tsi_ni].endport))) {
+- fitrange1 = 1;
+- DBG(DBG_CONTROL,DBG_log(" tsi[%d] %d == ei->port %d exact match single port fitrange1 %d"
+- ,tsi_ni, tsi[tsi_ni].startport, ei->port, fitrange1));
+-
+- }
+- else if ((!ei->port) && ( ( tsi[tsi_ni].startport == ei->port ) && (tsi[tsi_ni].endport == 65535 ))) {
+- // we are on range 0 - 64K will alloow only the same with our without narrowing
+- fitrange1 = 65535;
+- DBG(DBG_CONTROL,DBG_log(" tsi[%d] %d-%d == ei 0-65535 exact match all ports fitrange1 %d"
+- ,tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport, fitrange1));
++
++ hp = find_host_pair(&c->spd.this.host_addr
++ , c->spd.this.host_port
++ , &c->spd.that.host_addr
++ , c->spd.that.host_port);
++
++#ifdef DEBUG
++ if (DBGP(DBG_CONTROLMORE))
++ {
++ char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF];
++
++ subnettot(&c->spd.this.client, 0, s2, sizeof(s2));
++ subnettot(&c->spd.that.client, 0, d2, sizeof(d2));
++
++ DBG_log(" checking hostpair %s -> %s is %s"
++ , s2, d2
++ , (hp ? "found" : "not found"));
++ }
++#endif /* DEBUG */
++
++ if(!hp) {
++ return FALSE;
++ }
++
++ /* check if there is any specific first traffic selector */
++ if( addrcmp(&tsi[0].low, &tsi[0].high)==0 && tsi[0].startport == tsi[0].endport && tsi[0].ipprotoid!=0
++ && addrcmp(&tsr[0].low, &tsr[0].high)==0 && tsr[0].startport == tsr[0].endport && tsr[0].ipprotoid!=0) {
++ specific_first_ts = TRUE;
++ }
++
++ /*if(!specific_first_ts && (tsi_n >= 2 || tsr_n >= 2) )
++ {
++ return FALSE;
++ }*/
++
++ for (d = hp->connections; d != NULL; d = d->hp_next)
++ {
++ int wildcards, pathlen; /* XXX */
++ struct traffic_selector tmp, tmp2;
++ int curs=0;
++ bool found_one_match_tsi = FALSE, found_one_match_tsr = FALSE;
++
++ if (d->policy & POLICY_GROUP)
++ continue;
++
++ if (!(same_id(&c->spd.this.id, &d->spd.this.id)
++ && match_id(&c->spd.that.id, &d->spd.that.id, &wildcards)
++ && trusted_ca(c->spd.that.ca, d->spd.that.ca, &pathlen)))
++ continue;
++
++
++ if(ikev2_perfect_match_ts(tsi, tsr, tsi_n, tsr_n, d, role)) {
++ *result = d;
++ return TRUE;
++ }
++
++ if(role == INITIATOR) {
++ ei = &d->spd.this;
++ er = &d->spd.that;
++ } else {
++ ei = &d->spd.that;
++ er = &d->spd.this;
++ }
++
++ tmp = ikev2_subnettots(ei);
++
++
++ for(i=0; i<tsi_n; i++) {
++
++ /* ip address */
++ if(addrcmp(&tmp.low, &tsi[i].low) >= 0)
++ {
++ tmp2.low = tmp.low;
++ }
++ else
++ {
++ tmp2.low = tsi[i].low;
++ }
++
++ if(addrcmp(&tmp.high, &tsi[i].high) >= 0)
++ {
++ tmp2.high = tsi[i].high;
++ }
++ else
++ {
++ tmp2.high = tmp.high;
++ }
++
++ if(addrcmp(&tmp2.low, &tmp2.high) > 0) {
++ continue;
++ }
++
++ if(addrtypeof(&tmp2.low) != addrtypeof(&tmp2.high)) {
++ continue;
++ }
++
++ /* port */
++ if(tmp.startport >= tsi[i].startport )
++ {
++ tmp2.startport=tmp.startport;
++ }
++ else
++ {
++ tmp2.startport=tsi[i].startport;
++ }
++
++ if(tmp.endport >= tsi[i].endport )
++ {
++ tmp2.endport=tsi[i].endport;
++ }
++ else
++ {
++ tmp2.endport=tmp.endport;
++ }
++
++ if(tmp2.startport > tmp2.endport)
++ {
++ continue;
++ }
++
++ /* protocol */
++ if( !tmp.ipprotoid && !tsi[i].ipprotoid && tmp.ipprotoid!=tsi[i].ipprotoid )
++ {
++ continue;
++ }
++
++ curs++;
++ found_one_match_tsi = TRUE;
++ }
++
++ tmp = ikev2_subnettots(er);
++ for(i=0; i<tsr_n; i++) {
++
++ /* ip address */
++ if(addrcmp(&tmp.low, &tsr[i].low) >= 0)
++ {
++ tmp2.low = tmp.low;
++ }
++ else
++ {
++ tmp2.low = tsr[i].low;
++ }
++
++ if(addrcmp(&tmp.high, &tsr[i].high) >= 0)
++ {
++ tmp2.high = tsr[i].high;
++ }
++ else
++ {
++ tmp2.high = tmp.high;
++ }
++
++ if(addrcmp(&tmp2.low, &tmp2.high) > 0) {
++ continue;
++ }
++
++ if(addrtypeof(&tmp2.low) != addrtypeof(&tmp2.high)) {
++ continue;
++ }
++
++ /* port */
++ if(tmp.startport >= tsr[i].startport )
++ {
++ tmp2.startport=tmp.startport;
++ }
++ else
++ {
++ tmp2.startport=tsr[i].startport;
++ }
++
++ if(tmp.endport >= tsr[i].endport )
++ {
++ tmp2.endport=tsr[i].endport;
++ }
++ else
++ {
++ tmp2.endport=tmp.endport;
++ }
++
++ if(tmp2.startport > tmp2.endport)
++ {
++ continue;
++ }
++
++ /* protocol */
++ if( !tmp.ipprotoid && !tsr[i].ipprotoid && tmp.ipprotoid!=tsr[i].ipprotoid )
++ {
++ continue;
++ }
++
++ curs++;
++ found_one_match_tsr = TRUE;
++
++ }
++
++ if(curs > bests && found_one_match_tsi && found_one_match_tsr)
++ {
++ bests = curs;
++ bestc = d;
++
++ }
++ }
++
++ if(bestc == NULL) {
++ return FALSE;
++ }
++
++ /* creating narrowed traffic selector */
++ {
++ struct traffic_selector tmp, tmp2, *tmp3;
++
++ *result = bestc;
++
++ if(role == INITIATOR) {
++ ei = &bestc->spd.this;
++ er = &bestc->spd.that;
++ } else {
++ ei = &bestc->spd.that;
++ er = &bestc->spd.this;
++ }
++
++
++ tmp = ikev2_subnettots(ei);
++ for(i=0; i<tsi_n; i++) {
++
++ /* ip address */
++ if(addrcmp(&tmp.low, &tsi[i].low) >= 0)
++ {
++ tmp2.low = tmp.low;
++ }
++ else
++ {
++ tmp2.low = tsi[i].low;
++ }
++
++ if(addrcmp(&tmp.high, &tsi[i].high) >= 0)
++ {
++ tmp2.high = tsi[i].high;
++ }
++ else
++ {
++ tmp2.high = tmp.high;
++ }
++
++ if(addrcmp(&tmp2.low, &tmp2.high) > 0) {
++ continue;
++ }
++
++ /* port */
++ if(tmp.startport >= tsi[i].startport )
++ {
++ tmp2.startport=tmp.startport;
++ }
++ else
++ {
++ tmp2.startport=tsi[i].startport;
++ }
++
++ if(tmp.endport >= tsi[i].endport )
++ {
++ tmp2.endport=tsi[i].endport;
++ }
++ else
++ {
++ tmp2.endport=tmp.endport;
++ }
++
++ if(tmp2.startport > tmp2.endport)
++ {
++ continue;
++ }
++
++ /* as openswan supports only single port, so picking one port*/
++ if( tmp2.startport > 0){
++ tmp2.endport = tmp2.startport;
++ }
++ else if (tmp2.endport < 65535 ){
++ tmp2.startport = tmp2.endport;
++ }
++
++ /* protocol */
++ if( tmp.ipprotoid > 0 && tsi[i].ipprotoid > 0 && tmp.ipprotoid!=tsi[i].ipprotoid)
++ {
++ continue;
++ }
++ else if(tmp.ipprotoid == 0)
++ {
++ tmp2.ipprotoid = tsi[i].ipprotoid;
+ }
+- else if ( (role == INITIATOR) && narrowing && (!ei->port)) {
+- DBG(DBG_CONTROL,DBG_log(" narrowing=yes want to narrow ei->port 0-65355 to tsi[%d] %d-%d"
+- ,tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport));
+- if( tsi[tsi_ni].startport <= tsi[tsi_ni].endport ) {
+- fitrange1 = 1 + tsi[tsi_ni].endport - tsi[tsi_ni].startport ;
+- DBG(DBG_CONTROL,DBG_log(" tsi[%d] %d-%d >= ei->port 0-65535 can be narrowed fitrange1 %d"
+- ,tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport, fitrange1));
+- }
+- else
+- DBG(DBG_CONTROL,DBG_log(" cant narrow tsi[%d] %d-%d to ei->port %d"
+- ,tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport, ei->port));
++ else
++ {
++ tmp2.ipprotoid = tmp.ipprotoid;
++ }
+
++ /*setting type */
++ switch(tmp2.low.u.v4.sin_family) {
++ case AF_INET:
++ tmp2.ts_type = IKEv2_TS_IPV4_ADDR_RANGE;
++ break;
++ case AF_INET6:
++ tmp2.ts_type = IKEv2_TS_IPV6_ADDR_RANGE;
++ break;
+ }
+- else if ((role == RESPONDER) && ( narrowing && ei->port) ) {
+- DBG(DBG_CONTROL,DBG_log(" narrowing=yes want to narrow ei->port %d to tsi[%d] %d-%d to"
+- ,ei->port, tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport));
+- if(( ei->port >= tsi[tsi_ni].startport ) &&
+- (ei->port <= tsi[tsi_ni].endport)) {
+- fitrange1 = 1 ;
+- DBG(DBG_CONTROL,DBG_log(" tsi[%d] %d-%d >= ei->port 0-65535. can be narrowed fitrange1 %d"
+- ,tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport, fitrange1));
++
++ tmp3 = alloc_thing(struct traffic_selector, "struct traffic_selector");
++ *tmp3 = tmp2;
++ tmp3->next = NULL;
++
++ if(*narrowed_tsi == NULL)
++ {
++ *narrowed_tsi = tmp3;
++ }
++ else
++ {
++ struct traffic_selector *tmp4 = *narrowed_tsi;
++ while(tmp4->next!=NULL){
++ tmp4 = tmp4->next;
+ }
+- else
+- DBG(DBG_CONTROL,DBG_log(" cant narrow tsi[%d] %d-%d to ei->port %d"
+- ,tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport, ei->port));
++ tmp4->next = tmp3;
++
++ }
++ }
++
++ tmp = ikev2_subnettots(er);
++ for(i=0; i<tsr_n; i++) {
++
++ /* ip address */
++ if(addrcmp(&tmp.low, &tsr[i].low) >= 0)
++ {
++ tmp2.low = tmp.low;
++ }
++ else
++ {
++ tmp2.low = tsr[i].low;
++ }
++
++ if(addrcmp(&tmp.high, &tsr[i].high) >= 0)
++ {
++ tmp2.high = tsr[i].high;
++ }
++ else
++ {
++ tmp2.high = tmp.high;
++ }
+
++ if(addrcmp(&tmp2.low, &tmp2.high) > 0) {
++ continue;
+ }
+
++ /* port */
++ if(tmp.startport >= tsr[i].startport )
++ {
++ tmp2.startport=tmp.startport;
++ }
+ else
+- DBG(DBG_CONTROL,DBG_log(" mismatch tsi[%d] %d-%d to ei->port %d"
+- ,tsi_ni, tsi[tsi_ni].startport, tsi[tsi_ni].endport, ei->port));
++ {
++ tmp2.startport=tsr[i].startport;
++ }
+
++ if(tmp.endport >= tsr[i].endport )
++ {
++ tmp2.endport=tsr[i].endport;
++ }
++ else
++ {
++ tmp2.endport=tmp.endport;
++ }
++
++ if(tmp2.startport > tmp2.endport)
++ {
++ continue;
++ }
+
+- if((er->port) && (( er->port == tsr[tsr_ni].startport ) && (er->port == tsr[tsr_ni].endport))) {
+- fitrange2 = 1;
+- DBG(DBG_CONTROL,DBG_log(" tsr[%d] %d == er->port %d exact match single port fitrange2 %d"
+- ,tsr_ni, tsr[tsr_ni].startport, er->port, fitrange2));
++ /* as openswan supports only single port, so picking one port*/
++ if( tmp2.startport > 0){
++ tmp2.endport = tmp2.startport;
++ }
++ else if (tmp2.endport < 65535 ){
++ tmp2.startport = tmp2.endport;
++ }
+
++ /* protocol */
++ if( !tmp.ipprotoid && !tsr[i].ipprotoid && tmp.ipprotoid!=tsr[i].ipprotoid )
++ {
++ continue;
+ }
+- else if ((!er->port) && ( ( tsr[tsr_ni].startport == er->port ) && (tsr[tsr_ni].endport == 65535 ))) {
+- // we are on range 0 - 64K will alloow only the same with our without narrowing
+- fitrange2 = 65535;
+- DBG(DBG_CONTROL,DBG_log(" tsr[%d] %d-%d == ei 0-65535 exact match all ports fitrange2 %d"
+- , tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport, fitrange2));
++ else if(tmp.ipprotoid == 0)
++ {
++ tmp2.ipprotoid = tsr[i].ipprotoid;
+ }
++ else
++ {
++ tmp2.ipprotoid = tmp.ipprotoid;
++ }
+
+- else if ( (role == INITIATOR) && narrowing && (!er->port)) {
+- DBG(DBG_CONTROL,DBG_log(" narrowing=yes want to narrow ei->port 0-65355 to tsi[%d] %d-%d"
+- ,tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport));
+- if( tsr[tsr_ni].startport <= tsi[tsr_ni].endport ){
+- fitrange2 = 1 + tsr[tsr_ni].endport - tsr[tsi_ni].startport;
+- DBG(DBG_CONTROL,DBG_log(" tsr[%d] %d-%d <= er->port 0-65535 can be narrowed fitrange2 %d"
+- ,tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport,fitrange2));
+- }
+- else
+- DBG(DBG_CONTROL,DBG_log(" cant narrow tsr[%d] %d-%d to er->port 0-65535"
+- ,tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport));
++ /*setting type */
++ switch(tmp2.low.u.v4.sin_family) {
++ case AF_INET:
++ tmp2.ts_type = IKEv2_TS_IPV4_ADDR_RANGE;
++ break;
++ case AF_INET6:
++ tmp2.ts_type = IKEv2_TS_IPV6_ADDR_RANGE;
++ break;
++ }
+
+- }
+- else if ((role == RESPONDER) && narrowing && (er->port)) {
+- DBG(DBG_CONTROL,DBG_log(" narrowing=yes want to narrow ei->port 0-65535 to tsi[%d] %d-%d"
+- ,tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport));
+- if(( er->port >= tsr[tsr_ni].startport ) &&
+- (er->port <= tsr[tsr_ni].endport)) {
+- fitrange2 = 1;
+- DBG(DBG_CONTROL,DBG_log(" tsr[%d] %d-%d <= er->port %d can be narrowed fitrange2 %d"
+- , tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport, er->port, fitrange2));
+- }
+- else
+- DBG(DBG_CONTROL,DBG_log(" can't narrow tsr[%d] %d-%d to er->port %d"
+- , tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport, er->port));
++ tmp3 = alloc_thing(struct traffic_selector, "struct traffic_selector");
++ *tmp3 = tmp2;
++ tmp3->next = NULL;
++
++ if(*narrowed_tsr == NULL)
++ {
++ *narrowed_tsr = tmp3;
+ }
+- else
+- DBG(DBG_CONTROL,DBG_log(" mismatch tsr[%d] %d-%d to er->port %d"
+- ,tsr_ni, tsr[tsr_ni].startport, tsr[tsr_ni].endport, er->port));
+-
+-
+- int fitbits = 0;
+- if(fitrange1 && fitrange2) {
+- fitbits = (fitrange1 << 8) + fitrange2;
+- DBG(DBG_CONTROL,DBG_log(" is a match"));
+- if(fitbits > bestfit_p) {
+- *best_tsi_i = tsi_ni;
+- *best_tsr_i = tsr_ni;
+- bestfit_p = fitbits;
+- DBG(DBG_CONTROL,DBG_log(" and is a better fit tsi[%d] fitrange1 %d tsr[%d] fitrange2 %d fitbits %d"
+- , *best_tsi_i, fitrange1 , *best_tsr_i, fitrange2, fitbits));
+- }
+- else {
+- DBG(DBG_CONTROL,DBG_log(" and is not a better fit tsi[%d] fitrange %d tsr[%d] fitrange2 %d fitbits %d"
+- , *best_tsi_i, fitrange1 , *best_tsr_i, fitrange2, fitbits));
++ else
++ {
++ struct traffic_selector *tmp4 = *narrowed_tsr;
++ while(tmp4->next!=NULL){
++ tmp4 = tmp4->next;
+ }
+- }
+- else {
+- DBG(DBG_CONTROL,DBG_log(" is not a match"));
++
++ tmp4->next = tmp3;
+ }
+
+ }
+ }
+- DBG(DBG_CONTROL,DBG_log(" port_fitness %d", bestfit_p));
+- return bestfit_p;
+-}
+-
+-int ikev2_evaluate_connection_fit(struct connection *d
+- , struct spd_route *sr
+- , enum phase1_role role
+- , struct traffic_selector *tsi
+- , struct traffic_selector *tsr
+- , unsigned int tsi_n
+- , unsigned int tsr_n)
+-{
+- unsigned int tsi_ni, tsr_ni;
+- int bestfit = -1;
+- int best_tsr, best_tsi;
+- struct end *ei, *er;
+-
+- if(role == INITIATOR) {
+- ei = &sr->this;
+- er = &sr->that;
+- } else {
+- ei = &sr->that;
+- er = &sr->this;
+- }
+-
+- DBG(DBG_CONTROLMORE,
+- {
+- char ei3[SUBNETTOT_BUF];
+- char er3[SUBNETTOT_BUF];
+- subnettot(&ei->client, 0, ei3, sizeof(ei3));
+- subnettot(&er->client, 0, er3, sizeof(er3));
+- DBG_log(" ikev2_evaluate_connection_fit evaluating our "
+- "I=%s:%s:%d/%d R=%s:%d/%d %s to their:"
+- , d->name, ei3, ei->protocol, ei->port
+- , er3, er->protocol, er->port
+- , is_virtual_connection(d) ? "(virt)" : "");
+- }
+- );
+-
+- /* compare tsi/r array to this/that, evaluating how well it fits */
+- for(tsi_ni = 0; tsi_ni < tsi_n; tsi_ni++) {
+- for(tsr_ni=0; tsr_ni<tsr_n; tsr_ni++) {
+- /* does it fit at all? */
+
++ struct traffic_selector *tmp;
++ tmp = *narrowed_tsi;
++ while(tmp!= NULL) {
++
+ DBG(DBG_CONTROLMORE,
+ {
+ char lbi[ADDRTOT_BUF];
+ char hbi[ADDRTOT_BUF];
+- char lbr[ADDRTOT_BUF];
+- char hbr[ADDRTOT_BUF];
+- addrtot(&tsi[tsi_ni].low, 0, lbi, sizeof(lbi));
+- addrtot(&tsi[tsi_ni].high, 0, hbi, sizeof(hbi));
+- addrtot(&tsr[tsr_ni].low, 0, lbr, sizeof(lbr));
+- addrtot(&tsr[tsr_ni].high, 0, hbr, sizeof(hbr));
++ addrtot(&tmp->low, 0, lbi, sizeof(lbi));
++ addrtot(&tmp->high, 0, hbi, sizeof(hbi));
+
+- DBG_log(" tsi[%u]=%s/%s proto=%d portrange %d-%d, tsr[%u]=%s/%s proto=%d portrange %d-%d"
+- , tsi_ni, lbi, hbi
+- , tsi[tsi_ni].ipprotoid, tsi[tsi_ni].startport, tsi[tsi_ni].endport
+- , tsr_ni, lbr, hbr
+- , tsr[tsr_ni].ipprotoid, tsr[tsr_ni].startport, tsr[tsr_ni].endport);
++ DBG_log(" tsi=%s/%s, port=%d/%d, protocol=%d"
++ , lbi, hbi, tmp->startport, tmp->endport, tmp->ipprotoid);
+ }
+ );
+- /* do addresses fit into the policy? */
+-
+- /*
+- * NOTE: Our parser/config only allows 1 CIDR, however IKEv2 ranges can be non-CIDR
+- * for now we really support/limit ourselves to a single CIDR
+- */
+- if(addrinsubnet(&tsi[tsi_ni].low, &ei->client)
+- && addrinsubnet(&tsi[tsi_ni].high, &ei->client)
+- && addrinsubnet(&tsr[tsr_ni].low, &er->client)
+- && addrinsubnet(&tsr[tsr_ni].high, &er->client)
+- && (tsi[tsi_ni].ipprotoid == ei->protocol)
+- && (tsr[tsr_ni].ipprotoid == er->protocol)
+- )
++
++ tmp=tmp->next;
++ }
++
++ tmp = *narrowed_tsr;
++ while(tmp!= NULL) {
++
++ DBG(DBG_CONTROLMORE,
+ {
+- /*
+- * now, how good a fit is it? --- sum of bits gives
+- * how good a fit this is.
+- */
+- int ts_range1 = ikev2_calc_iprangediff(tsi[tsi_ni].low
+- , tsi[tsi_ni].high);
+- int maskbits1 = ei->client.maskbits;
+- int fitbits1 = maskbits1 + ts_range1;
+-
+- int ts_range2 = ikev2_calc_iprangediff(tsr[tsr_ni].low
+- , tsr[tsr_ni].high);
+- int maskbits2 = er->client.maskbits;
+- int fitbits2 = maskbits2 + ts_range2;
+- int fitbits = (fitbits1 << 8) + fitbits2;
+-
+- /*
+- * comparing for ports
+- * for finding better local polcy
+- */
+- DBG(DBG_CONTROL,DBG_log("ei->port %d tsi[tsi_ni].startport %d tsi[tsi_ni].endport %d",
+- ei->port , tsi[tsi_ni].startport, tsi[tsi_ni].endport));
+- if( ei->port && (tsi[tsi_ni].startport == ei->port && tsi[tsi_ni].endport == ei->port)) {
+- fitbits = fitbits << 1;
+- }
++ char lbi[ADDRTOT_BUF];
++ char hbi[ADDRTOT_BUF];
++ addrtot(&tmp->low, 0, lbi, sizeof(lbi));
++ addrtot(&tmp->high, 0, hbi, sizeof(hbi));
++
++ DBG_log(" tsr=%s/%s, port=%d/%d, protocol=%d"
++ , lbi, hbi, tmp->startport, tmp->endport, tmp->ipprotoid);
++ }
++ );
+
+- if( er->port && (tsr[tsr_ni].startport == er->port && tsr[tsr_ni].endport == er->port)) {
+- fitbits = fitbits << 1;
+- }
++ tmp=tmp->next;
++ }
++ return TRUE;
++}
+
+- DBG(DBG_CONTROLMORE,
+- {
+- DBG_log(" has ts_range1=%u maskbits1=%u ts_range2=%u maskbits2=%u fitbits=%d <> %d"
+- , ts_range1, maskbits1, ts_range2, maskbits2
+- , fitbits, bestfit);
+- }
+- );
++struct connection *
++ikev2_create_narrowed_con(struct connection *c
++ , struct traffic_selector *narrowed_tsi
++ , struct traffic_selector *narrowed_tsr
++ , enum phase1_role role)
++{
++ struct connection *narrowed_con=NULL;
++ struct spd_route *tmp_spd=NULL, *tmp_spd1=NULL;
++ struct traffic_selector *tmptsi=NULL, *tmptsr=NULL;
+
+- if(fitbits > bestfit) {
+- best_tsi = tsi_ni;
+- best_tsr = tsr_ni;
+- bestfit = fitbits;
++ narrowed_con = ikev2_narrow_instantiate(c);
++
++ /* setup spds for narrowed connection*/
++ tmp_spd1 = NULL;
++ tmp_spd = &narrowed_con->spd;
++ tmptsi = narrowed_tsi;
++
++ while(tmptsi != NULL) {
++ ip_subnet tmpsubneti;
++ rangetosubnet(&tmptsi->low, &tmptsi->high, &tmpsubneti);
++ tmptsr = narrowed_tsr;
++
++ while(tmptsr != NULL ) {
++ ip_subnet tmpsubnetr;
++ rangetosubnet(&tmptsr->low, &tmptsr->high, &tmpsubnetr);
++
++ if(tmp_spd == NULL) {
++ struct spd_route *tmp_spd2 = clone_thing(narrowed_con->spd, "spds from narrowed ts");
++ tmp_spd = tmp_spd2;
++ tmp_spd->next = NULL;
++
++ if(tmp_spd1!= NULL){
++ tmp_spd1->next = tmp_spd;
++ }
++
++ if(tmp_spd != &narrowed_con->spd) {
++ tmp_spd->this.id.name.ptr = NULL;
++ tmp_spd->this.id.name.len = 0;
++ tmp_spd->that.id.name.ptr = NULL;
++ tmp_spd->that.id.name.len = 0;
++
++ tmp_spd->this.host_addr_name = NULL;
++ tmp_spd->that.host_addr_name = NULL;
++
++ tmp_spd->this.updown = clone_str(tmp_spd->this.updown, "updown");
++ tmp_spd->that.updown = clone_str(tmp_spd->that.updown, "updown");
++
++ tmp_spd->this.cert_filename = NULL;
++ tmp_spd->that.cert_filename = NULL;
++
++ tmp_spd->this.cert.type = 0;
++ tmp_spd->that.cert.type = 0;
++
++ tmp_spd->this.ca.ptr = NULL;
++ tmp_spd->that.ca.ptr = NULL;
++
++ tmp_spd->this.groups = NULL;
++ tmp_spd->that.groups = NULL;
++
++ tmp_spd->this.virt = NULL;
++ tmp_spd->that.virt = NULL;
++ }
++ }
++
++ if(role == INITIATOR) {
++ tmp_spd->this.client = tmpsubneti;
++ tmp_spd->this.port = tmptsi->startport;
++ tmp_spd->this.protocol = tmptsi->ipprotoid;
++ if( subnetishost(&tmp_spd->this.client) && addrinsubnet(&tmp_spd->this.host_addr, &tmp_spd->this.client)) {
++ tmp_spd->this.has_client = FALSE;
++ }
++ else {
++ tmp_spd->this.has_client = TRUE;
++ }
++ tmp_spd->this.has_client_wildcard = FALSE;
++ tmp_spd->this.has_port_wildcard = FALSE;
++ setportof(htons(tmp_spd->this.port), &tmp_spd->this.host_addr);
++ setportof(htons(tmp_spd->this.port), &tmp_spd->this.client.addr);
++
++ tmp_spd->that.client = tmpsubnetr;
++ tmp_spd->that.port = tmptsr->startport;
++ tmp_spd->that.protocol = tmptsr->ipprotoid;
++ if( subnetishost(&tmp_spd->that.client) && addrinsubnet(&tmp_spd->that.host_addr, &tmp_spd->that.client)) {
++ tmp_spd->that.has_client = FALSE;
++ }
++ else {
++ tmp_spd->that.has_client = TRUE;
++ }
++ tmp_spd->that.has_client_wildcard = FALSE;
++ tmp_spd->that.has_port_wildcard = FALSE;
++ setportof(htons(tmp_spd->that.port), &tmp_spd->that.host_addr);
++ setportof(htons(tmp_spd->that.port), &tmp_spd->that.client.addr);
++ }
++ else {
++ tmp_spd->this.client = tmpsubnetr;
++ tmp_spd->this.port = tmptsr->startport;
++ tmp_spd->this.protocol = tmptsr->ipprotoid;
++ if( subnetishost(&tmp_spd->this.client) && addrinsubnet(&tmp_spd->this.host_addr, &tmp_spd->this.client)) {
++ tmp_spd->this.has_client = FALSE;
++ }
++ else {
++ tmp_spd->this.has_client = TRUE;
++ }
++ tmp_spd->this.has_client_wildcard = FALSE;
++ tmp_spd->this.has_port_wildcard = FALSE;
++ setportof(htons(tmp_spd->this.port), &tmp_spd->this.host_addr);
++ setportof(htons(tmp_spd->this.port), &tmp_spd->this.client.addr);
++
++ tmp_spd->that.client = tmpsubneti;
++ tmp_spd->that.port = tmptsi->startport;
++ tmp_spd->that.protocol = tmptsi->ipprotoid;
++ if( subnetishost(&tmp_spd->that.client) && addrinsubnet(&tmp_spd->that.host_addr, &tmp_spd->that.client)) {
++ tmp_spd->that.has_client = FALSE;
++ }
++ else {
++ tmp_spd->that.has_client = TRUE;
++ }
++ tmp_spd->that.has_client_wildcard = FALSE;
++ tmp_spd->that.has_port_wildcard = FALSE;
++ setportof(htons(tmp_spd->that.port), &tmp_spd->that.host_addr);
++ setportof(htons(tmp_spd->that.port), &tmp_spd->that.client.addr);
++ }
++
++ tmp_spd1 = tmp_spd;
++ tmp_spd = tmp_spd1->next;
++ tmptsr = tmptsr->next;
+ }
+- }
++ tmptsi = tmptsi->next;
+ }
+- }
+
+- return bestfit;
++ char buftest[ADDRTOT_BUF];
++ tmp_spd = &narrowed_con->spd;
++ int count_spd=0;
++ do {
++ DBG(DBG_CONTROLMORE, DBG_log("spd route number: %d", ++count_spd));
++
++ /**that info**/
++ DBG(DBG_CONTROLMORE, DBG_log("that id kind: %d",tmp_spd->that.id.kind));
++ DBG(DBG_CONTROLMORE,
++ DBG_log("that id ipaddr: %s", (addrtot(&tmp_spd->that.id.ip_addr, 0, buftest, sizeof(buftest)), buftest)));
++
++ if (tmp_spd->that.id.name.ptr != NULL) {
++ DBG(DBG_CONTROLMORE, DBG_dump_chunk("that id name",tmp_spd->that.id.name));
++ }
++
++ DBG(DBG_CONTROLMORE,
++ DBG_log("that host_addr: %s", (addrtot(&tmp_spd->that.host_addr, 0, buftest, sizeof(buftest)), buftest)));
++ DBG(DBG_CONTROLMORE,
++ DBG_log("that nexthop: %s", (addrtot(&tmp_spd->that.host_nexthop, 0, buftest, sizeof(buftest)), buftest)));
++ DBG(DBG_CONTROLMORE,
++ DBG_log("that srcip: %s", (addrtot(&tmp_spd->that.host_srcip, 0, buftest, sizeof(buftest)), buftest)));
++ DBG(DBG_CONTROLMORE,
++ DBG_log("that client_addr: %s, maskbits:%d", (addrtot(&tmp_spd->that.client.addr, 0,
++ buftest, sizeof(buftest)), buftest),tmp_spd->that.client.maskbits));
++ DBG(DBG_CONTROLMORE, DBG_log("that has_client: %d", tmp_spd->that.has_client));
++ DBG(DBG_CONTROLMORE, DBG_log("that has_client_wildcard: %d", tmp_spd->that.has_client_wildcard));
++ DBG(DBG_CONTROLMORE, DBG_log("that has_port_wildcard: %d", tmp_spd->that.has_port_wildcard));
++ DBG(DBG_CONTROLMORE, DBG_log("that has_id_wildcards: %d", tmp_spd->that.has_id_wildcards));
++
++ /**this info**/
++ DBG(DBG_CONTROLMORE, DBG_log("this id kind: %d",tmp_spd->this.id.kind));
++ DBG(DBG_CONTROLMORE,
++ DBG_log("this id ipaddr: %s", (addrtot(&tmp_spd->this.id.ip_addr, 0, buftest, sizeof(buftest)), buftest)));
++
++ if (tmp_spd->this.id.name.ptr != NULL) {
++ DBG_dump_chunk("this id name",tmp_spd->this.id.name);
++ }
++
++ DBG(DBG_CONTROLMORE,
++ DBG_log("this host_addr: %s", (addrtot(&tmp_spd->this.host_addr, 0, buftest, sizeof(buftest)), buftest)));
++ DBG(DBG_CONTROLMORE,
++ DBG_log("this nexthop: %s", (addrtot(&tmp_spd->this.host_nexthop, 0, buftest, sizeof(buftest)), buftest)));
++ DBG(DBG_CONTROLMORE,
++ DBG_log("this srcip: %s", (addrtot(&tmp_spd->this.host_srcip, 0, buftest, sizeof(buftest)), buftest)));
++ DBG(DBG_CONTROLMORE, DBG_log("this client_addr: %s, maskbits:%d", (addrtot(&tmp_spd->this.client.addr,
++ 0, buftest, sizeof(buftest)), buftest),tmp_spd->this.client.maskbits));
++ DBG(DBG_CONTROLMORE, DBG_log("this has_client: %d", tmp_spd->this.has_client));
++ DBG(DBG_CONTROLMORE, DBG_log("this has_client_wildcard: %d", tmp_spd->this.has_client_wildcard));
++ DBG(DBG_CONTROLMORE, DBG_log("this has_port_wildcard: %d", tmp_spd->this.has_port_wildcard));
++ DBG(DBG_CONTROLMORE, DBG_log("this has_id_wildcards: %d", tmp_spd->this.has_id_wildcards));
++
++ tmp_spd = tmp_spd->next;
++ } while(tmp_spd!=NULL);
++
++ return narrowed_con;
+ }
+
+ stf_status ikev2_child_sa_respond(struct msg_digest *md
+@@ -618,8 +1187,13 @@ stf_status ikev2_child_sa_respond(struct msg_digest *md
+ stf_status ret;
+ struct payload_digest *const tsi_pd = md->chain[ISAKMP_NEXT_v2TSi];
+ struct payload_digest *const tsr_pd = md->chain[ISAKMP_NEXT_v2TSr];
+- struct traffic_selector tsi[16], tsr[16];
++ struct traffic_selector tsi[16], tsr[16], *narrowed_tsi=NULL, *narrowed_tsr=NULL;
++ struct connection *narrowed_con=NULL, *result=NULL;
+ unsigned int tsi_n, tsr_n;
++ bool ts_negotiation_failed = FALSE;
++
++
++ st1 = duplicate_state(st);
+
+ /*
+ * now look at provided TSx, and see if these fit the connection
+@@ -628,195 +1202,117 @@ stf_status ikev2_child_sa_respond(struct msg_digest *md
+ tsi_n = ikev2_parse_ts(tsi_pd, tsi, 16);
+ tsr_n = ikev2_parse_ts(tsr_pd, tsr, 16);
+
+- /*
+- * now walk through all connections and see if this connection
+- * was in fact the best.
+- *
+- * similar to find_client_connection/fc_try.
+- */
+- {
+- struct connection *b = c;
+- struct connection *d;
+- int bestfit_n, newfit, bestfit_p;
+- struct spd_route *sra, *bsr;
+- struct host_pair *hp = NULL;
+- unsigned int best_tsi_i , best_tsr_i;
+-
+- bsr = NULL;
+- bestfit_n = -1;
+- bestfit_p = -1;
+- best_tsi_i = best_tsr_i = -1;
+-
+- for (sra = &c->spd; sra != NULL; sra = sra->next)
+- {
+- int bfit_n=ikev2_evaluate_connection_fit(c,sra,role,tsi,tsr,tsi_n,
+- tsr_n);
+- if (bfit_n > bestfit_n)
+- {
+- DBG(DBG_CONTROLMORE, DBG_log("bfit_n=ikev2_evaluate_connection_fit found better fit c %s", c->name));
+- int bfit_p = ikev2_evaluate_connection_port_fit (c ,sra,role,tsi,tsr,
+- tsi_n,tsr_n, &best_tsi_i, &best_tsr_i);
+- if (bfit_p > bestfit_p) {
+- DBG(DBG_CONTROLMORE, DBG_log("ikev2_evaluate_connection_port_fit found better fit c %s, tsi[%d],tsr[%d]"
+- , c->name, best_tsi_i, best_tsr_i));
+- bestfit_p = bfit_p;
+- bestfit_n = bfit_n;
+- b = c;
+- bsr = sra;
+- }
+- }
+- else
+- DBG(DBG_CONTROLMORE, DBG_log("prefix range fit c %s c->name was rejected by port matching"
+- , c->name));
+- }
+-
+- for (sra = &c->spd; hp==NULL && sra != NULL; sra = sra->next)
+- {
+- hp = find_host_pair(&sra->this.host_addr
+- , sra->this.host_port
+- , &sra->that.host_addr
+- , sra->that.host_port);
++ if(ikev2_narrowing(c, role, tsi, tsr, tsi_n, tsr_n, &narrowed_tsi , &narrowed_tsr, &result)){
+
+-#ifdef DEBUG
+- if (DBGP(DBG_CONTROLMORE))
+- {
+- char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF];
++ if(narrowed_tsi == NULL && narrowed_tsr == NULL && result!= NULL) {
++ /*found exact match */
++ narrowed_con = result;
+
+- subnettot(&sra->this.client, 0, s2, sizeof(s2));
+- subnettot(&sra->that.client, 0, d2, sizeof(d2));
++ /*preparing traffic selectors (need to do: free first narrowed_ts here) */
++ st1->st_ts_this= ikev2_subnettots(&result->spd.this);
++ st1->st_ts_that= ikev2_subnettots(&result->spd.that);
++ }
++ else {
++ narrowed_con = ikev2_create_narrowed_con(result, narrowed_tsi, narrowed_tsr, role);
+
+- DBG_log(" checking hostpair %s -> %s is %s"
+- , s2, d2
+- , (hp ? "found" : "not found"));
++ /*preparing traffic selectors (need to do: free first narrowed_ts here) */
++ if(role == INITIATOR) {
++ st1->st_ts_this= *narrowed_tsi;
++ st1->st_ts_that= *narrowed_tsr;
+ }
+-#endif /* DEBUG */
+-
+- if(!hp) continue;
+-
+- for (d = hp->connections; d != NULL; d = d->hp_next)
+- {
+- struct spd_route *sr;
+- int wildcards, pathlen; /* XXX */
+-
+- if (d->policy & POLICY_GROUP)
+- continue;
+-
+- if (!(same_id(&c->spd.this.id, &d->spd.this.id)
+- && match_id(&c->spd.that.id, &d->spd.that.id, &wildcards)
+- && trusted_ca(c->spd.that.ca, d->spd.that.ca, &pathlen)))
+- continue;
+-
+-
+- for (sr = &d->spd; sr != NULL; sr = sr->next) {
+- newfit=ikev2_evaluate_connection_fit(d,sr,role
+- ,tsi,tsr,tsi_n,tsr_n);
+- if(newfit > bestfit_n) { /// will complicated this with narrowing
+- DBG(DBG_CONTROLMORE, DBG_log("bfit=ikev2_evaluate_connection_fit found better fit d %s", d->name));
+- int bfit_p = ikev2_evaluate_connection_port_fit (c ,sra,role,tsi,tsr,
+- tsi_n,tsr_n, &best_tsi_i, &best_tsr_i);
+- if (bfit_p > bestfit_p) {
+- DBG(DBG_CONTROLMORE, DBG_log("ikev2_evaluate_connection_port_fit found better fit d %s, tsi[%d],tsr[%d]"
+- , d->name, best_tsi_i, best_tsr_i));
+- bestfit_p = bfit_p;
+- bestfit_n = newfit;
+- b = d;
+- bsr = sr;
+- }
+- }
+- else
+- DBG(DBG_CONTROLMORE, DBG_log("prefix range fit d %s d->name was rejected by port matching", d->name));
+- }
++ else {
++ st1->st_ts_this= *narrowed_tsr;
++ st1->st_ts_that= *narrowed_tsi;
+ }
++
++ pfreeany(narrowed_tsi);
++ pfreeany(narrowed_tsr);
+ }
++ }
++ else {
++ ts_negotiation_failed = TRUE;
++ }
+
+- /*
+- * now that we have found the best connection, copy the data into
+- * the state structure as the tsi/tsr
+- *
+- */
++ if(narrowed_con!= NULL && !ts_negotiation_failed) {
++ c = narrowed_con;
++ }
+
+- /*better connection*/
+- c=b;
++ st1->st_connection = c;
++ st1->st_childsa = NULL;
++ insert_state(st1);
+
+- /* Paul: should we STF_FAIL here instead of checking for NULL */
+- if (bsr != NULL) {
+- st1 = duplicate_state(st);
+- insert_state(st1); /* needed for delete - we should never have duplicated before we were sure */
+-
+- if(role == INITIATOR) {
+- memcpy (&st1->st_ts_this , &tsi[best_tsi_i], sizeof(struct traffic_selector));
+- memcpy (&st1->st_ts_that , &tsr[best_tsr_i], sizeof(struct traffic_selector));
+- }
+- else {
+- st1->st_ts_this = ikev2_end_to_ts(&bsr->this);
+- st1->st_ts_that = ikev2_end_to_ts(&bsr->that);
+- }
+- ikev2_print_ts(&st1->st_ts_this);
+- ikev2_print_ts(&st1->st_ts_that);
++ /* start of SA out */
++ {
++ struct isakmp_sa r_sa = sa_pd->payload.sa;
++ notification_t rn;
++ pb_stream r_sa_pbs;
++
++ if(ts_negotiation_failed) {
++ r_sa.isasa_np = ISAKMP_NEXT_v2N;
+ }
+ else {
+- if(role == INITIATOR)
+- return STF_FAIL;
+- else
+- return STF_FAIL + v2N_NO_PROPOSAL_CHOSEN ;
+- }
++ r_sa.isasa_np = ISAKMP_NEXT_v2TSi;
+ }
++
++ if (!out_struct(&r_sa, &ikev2_sa_desc, outpbs, &r_sa_pbs))
++ return STF_INTERNAL_ERROR;
+
+- st1->st_connection = c;
+- md->st = st1;
+- md->pst= st;
+-
+- /* start of SA out */
+- {
+- struct isakmp_sa r_sa = sa_pd->payload.sa;
+- notification_t rn;
+- pb_stream r_sa_pbs;
+-
+- r_sa.isasa_np = ISAKMP_NEXT_v2TSi;
+- if (!out_struct(&r_sa, &ikev2_sa_desc, outpbs, &r_sa_pbs))
+- return STF_INTERNAL_ERROR;
++ /* SA body in and out */
++ rn = ikev2_parse_child_sa_body(&sa_pd->pbs, &sa_pd->payload.v2sa,
++ &r_sa_pbs, st1, FALSE);
++
++ if (rn != NOTHING_WRONG)
++ return STF_FAIL + rn;
++ }
+
+- /* SA body in and out */
+- rn = ikev2_parse_child_sa_body(&sa_pd->pbs, &sa_pd->payload.v2sa,
+- &r_sa_pbs, st1, FALSE);
++ if(ts_negotiation_failed) {
++ chunk_t child_spi, notifiy_data;
++ memset(&child_spi, 0, sizeof(child_spi));
++ memset(¬ifiy_data, 0, sizeof(notifiy_data));
++ ship_v2N (ISAKMP_NEXT_NONE, ISAKMP_PAYLOAD_NONCRITICAL, /*PROTO_ISAKMP*/ 0,
++ &child_spi,
++ v2N_TS_UNACCEPTABLE, ¬ifiy_data, outpbs);
++ change_state(st1, STATE_CHILDSA_DEL);
++ delete_state(st1);
++ return STF_OK;
++ }
+
+- if (rn != NOTHING_WRONG)
+- return STF_FAIL + rn; // should we delete_state st1?
+- }
++ md->st = st1;
++ md->pst= st;
+
+ ret = ikev2_calc_emit_ts(md, outpbs, role
+ , c, c->policy);
+ if(ret != STF_OK) return ret; // should we delete_state st1?
+
+- if( role == RESPONDER ) {
+- chunk_t child_spi, notifiy_data;
+- struct payload_digest *p;
+- for(p = md->chain[ISAKMP_NEXT_v2N]; p != NULL; p = p->next)
+- {
+- if ( p->payload.v2n.isan_type == v2N_USE_TRANSPORT_MODE ) {
+-
+- if(st1->st_connection->policy & POLICY_TUNNEL) {
+- DBG_log("Although local policy is tunnel, received USE_TRANSPORT_MODE");
+- DBG_log("So switching to transport mode, and responding with USE_TRANSPORT_MODE notify");
+- }
+- else {
+- DBG_log("Local policy is transport, received USE_TRANSPORT_MODE");
+- DBG_log("Now responding with USE_TRANSPORT_MODE notify");
+- }
+-
+- memset(&child_spi, 0, sizeof(child_spi));
+- memset(¬ifiy_data, 0, sizeof(notifiy_data));
+- ship_v2N (ISAKMP_NEXT_NONE, ISAKMP_PAYLOAD_NONCRITICAL, /*PROTO_ISAKMP*/ 0,
+- &child_spi,
+- v2N_USE_TRANSPORT_MODE, ¬ifiy_data, outpbs);
+-
+- if (st1->st_esp.present == TRUE) {
+- /*openswan supports only "esp" with ikev2 it seems, look at ikev2_parse_child_sa_body handling*/
+- st1->st_esp.attrs.encapsulation = ENCAPSULATION_MODE_TRANSPORT;
+- }
+- break;
+- }
+- }
++ if( role == RESPONDER ) {
++ chunk_t child_spi, notifiy_data;
++ struct payload_digest *p;
++ for(p = md->chain[ISAKMP_NEXT_v2N]; p != NULL; p = p->next)
++ {
++ if ( p->payload.v2n.isan_type == v2N_USE_TRANSPORT_MODE ) {
++
++ if(st1->st_connection->policy & POLICY_TUNNEL) {
++ DBG_log("Although local policy is tunnel, received v2N_USE_TRANSPORT_MODE");
++ DBG_log("So switching to transport mode, and responding with v2N_USE_TRANSPORT_MODE notify");
++ }
++ else {
++ DBG_log("Local policy is transport, received v2N_USE_TRANSPORT_MODE");
++ DBG_log("Now responding with v2N_USE_TRANSPORT_MODE notify");
++ }
++
++ memset(&child_spi, 0, sizeof(child_spi));
++ memset(¬ifiy_data, 0, sizeof(notifiy_data));
++ ship_v2N (ISAKMP_NEXT_NONE, ISAKMP_PAYLOAD_NONCRITICAL, /*PROTO_ISAKMP*/ 0,
++ &child_spi,
++ v2N_USE_TRANSPORT_MODE, ¬ifiy_data, outpbs);
++
++ if (st1->st_esp.present == TRUE) {
++ /*openswan supports only "esp" with ikev2 it seems, look at ikev2_parse_child_sa_body handling*/
++ st1->st_esp.attrs.encapsulation = ENCAPSULATION_MODE_TRANSPORT;
++ }
++ break;
++ }
++ }
+ }
+
+ ikev2_derive_child_keys(st1, role);
+@@ -824,6 +1320,8 @@ stf_status ikev2_child_sa_respond(struct msg_digest *md
+ if(!install_ipsec_sa(st1, TRUE))
+ return STF_FATAL;
+
++ st1->st_childsa = c;
++
+ /* mark the connection as now having an IPsec SA associated with it. */
+ st1->st_connection->newest_ipsec_sa = st1->st_serialno;
+
+diff --git a/programs/pluto/ikev2_parent.c b/programs/pluto/ikev2_parent.c
+index 5b1940a..a96ede5 100644
+--- a/programs/pluto/ikev2_parent.c
++++ b/programs/pluto/ikev2_parent.c
+@@ -120,8 +120,9 @@ ikev2parent_outI1(int whack_sock
+ initialize_new_state(st, c, policy, try, whack_sock, importance);
+ st->st_ikev2 = TRUE;
+ change_state(st, STATE_PARENT_I1);
+- st->st_msgid_lastack = INVALID_MSGID;
+- st->st_msgid_nextuse = 0;
++ st->st_msgid_last_localreq = INVALID_MSGID;
++ st->st_msgid_last_localreq_ack = INVALID_MSGID;
++ st->st_msgid_last_remotereq=INVALID_MSGID;
+ st->st_try = try;
+
+ if (HAS_IPSEC_POLICY(policy)) {
+@@ -483,6 +484,7 @@ ikev2_parent_outI1_common(struct msg_digest *md
+
+ /* Transmit */
+ send_packet(st, __FUNCTION__, TRUE);
++ ikev2_update_counters(md, req_sent);
+
+ /* Set up a retransmission event, half a minute henceforth */
+ TCLCALLOUT("v2_adjustTimers", st, st->st_connection, md);
+@@ -565,8 +567,9 @@ stf_status ikev2parent_inI1outR1(struct msg_digest *md)
+ initialize_new_state(st, c, policy, 0, NULL_FD, pcim_stranger_crypto);
+ st->st_ikev2 = TRUE;
+ change_state(st, STATE_PARENT_R1);
+- st->st_msgid_lastack = INVALID_MSGID;
+- st->st_msgid_nextuse = 0;
++ st->st_msgid_last_localreq = INVALID_MSGID;
++ st->st_msgid_last_localreq_ack = INVALID_MSGID;
++ st->st_msgid_last_remotereq=INVALID_MSGID;
+
+ md->st = st;
+ md->from_state = STATE_IKEv2_BASE;
+@@ -750,6 +753,8 @@ ikev2_parent_inI1outR1_tail(struct pluto_crypto_req_cont *pcrc
+ {
+ struct isakmp_hdr r_hdr = md->hdr;
+
++ r_hdr.isa_version = IKEv2_MAJOR_VERSION << ISA_MAJ_SHIFT | IKEv2_MINOR_VERSION;
++
+ memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
+ r_hdr.isa_np = ISAKMP_NEXT_v2SA;
+ r_hdr.isa_flags &= ~ISAKMP_FLAGS_I;
+@@ -761,7 +766,7 @@ ikev2_parent_inI1outR1_tail(struct pluto_crypto_req_cont *pcrc
+
+ /* start of SA out */
+ {
+- struct isakmp_sa r_sa = sa_pd->payload.sa;
++ struct ikev2_sa r_sa = sa_pd->payload.v2sa;
+ v2_notification_t rn;
+ pb_stream r_sa_pbs;
+
+@@ -848,6 +853,8 @@ ikev2_parent_inI1outR1_tail(struct pluto_crypto_req_cont *pcrc
+
+ /* note: retransimission is driven by initiator */
+
++ ikev2_update_counters(md, response_sent);
++
+ return STF_OK;
+
+ }
+@@ -897,9 +904,9 @@ stf_status ikev2parent_inR1outI2(struct msg_digest *md)
+ md->svm = ikev2_parent_firststate();
+
+ change_state(st, STATE_PARENT_I1);
+- st->st_msgid_lastack = INVALID_MSGID;
+- md->msgid_received = INVALID_MSGID; /* AAA hack */
+- st->st_msgid_nextuse = 0;
++ st->st_msgid_last_localreq = INVALID_MSGID;
++ st->st_msgid_last_localreq_ack = INVALID_MSGID;
++ st->st_msgid_last_remotereq=INVALID_MSGID;
+
+ return ikev2_parent_outI1_common(md, st);
+ }
+@@ -954,8 +961,8 @@ stf_status ikev2parent_inR1outI2(struct msg_digest *md)
+ return STF_FAIL + rn;
+ }
+
+- /* update state */
+- ikev2_update_counters(md);
++ /* update state counters */
++ ikev2_update_counters(md, response_recd);
+
+ /* now. we need to go calculate the g^xy */
+ {
+@@ -1120,14 +1127,9 @@ static stf_status ikev2_encrypt_msg(struct msg_digest *md,
+ /* okay, authenticate from beginning of IV */
+ {
+ struct hmac_ctx ctx;
+- DBG(DBG_PARSING, DBG_log("Inside authloc"));
+- DBG(DBG_CRYPT, DBG_dump("authkey value: ", authkey->ptr, authkey->len));
+ hmac_init_chunk(&ctx, pst->st_oakley.integ_hasher, *authkey);
+- DBG(DBG_PARSING, DBG_log("Inside authloc after init"));
+ hmac_update(&ctx, authstart, authloc-authstart);
+- DBG(DBG_PARSING, DBG_log("Inside authloc after update"));
+ hmac_final(authloc, &ctx);
+- DBG(DBG_PARSING, DBG_log("Inside authloc after final"));
+
+ DBG(DBG_PARSING,
+ DBG_dump("data being hmac:", authstart, authloc-authstart);
+@@ -1317,7 +1319,7 @@ ikev2_parent_inR1outI2_tail(struct pluto_crypto_req_cont *pcrc
+
+ pst = st;
+ st = duplicate_state(pst);
+- st->st_msgid = htonl(pst->st_msgid_nextuse); /* PAUL: note ordering */
++ st->st_msgid = htonl(pst->st_msgid_last_localreq == INVALID_MSGID? 0 : pst->st_msgid_last_localreq + 1);
+ insert_state(st);
+ md->st = st;
+ md->pst= pst;
+@@ -1344,6 +1346,8 @@ ikev2_parent_inR1outI2_tail(struct pluto_crypto_req_cont *pcrc
+ {
+ struct isakmp_hdr r_hdr = md->hdr;
+
++ r_hdr.isa_version = IKEv2_MAJOR_VERSION << ISA_MAJ_SHIFT | IKEv2_MINOR_VERSION;
++
+ r_hdr.isa_np = ISAKMP_NEXT_v2E;
+ r_hdr.isa_xchg = ISAKMP_v2_AUTH;
+ r_hdr.isa_flags = ISAKMP_FLAGS_I;
+@@ -1464,8 +1468,8 @@ ikev2_parent_inR1outI2_tail(struct pluto_crypto_req_cont *pcrc
+
+ ikev2_emit_ipsec_sa(md,&e_pbs_cipher,ISAKMP_NEXT_v2TSi,c0, policy);
+
+- st->st_ts_this = ikev2_end_to_ts(&c0->spd.this);
+- st->st_ts_that = ikev2_end_to_ts(&c0->spd.that);
++ st->st_ts_this = ikev2_subnettots(&c0->spd.this);
++ st->st_ts_that = ikev2_subnettots(&c0->spd.that);
+
+ ikev2_calc_emit_ts(md, &e_pbs_cipher, INITIATOR, c0, policy);
+
+@@ -1522,6 +1526,7 @@ ikev2_parent_inR1outI2_tail(struct pluto_crypto_req_cont *pcrc
+ delete_event(st);
+ event_schedule(EVENT_v2_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st);
+
++ ikev2_update_counters(md, req_sent);
+ return STF_OK;
+
+ }
+@@ -1648,7 +1653,6 @@ ikev2_parent_inI2outR2_tail(struct pluto_crypto_req_cont *pcrc
+ unsigned char *idhash_in, *idhash_out;
+ unsigned char *authstart;
+ unsigned int np;
+- int v2_notify_num = 0;
+
+ /* extract calculated values from r */
+ finish_dh_v2(st, r);
+@@ -1672,6 +1676,12 @@ ikev2_parent_inI2outR2_tail(struct pluto_crypto_req_cont *pcrc
+ return STF_FAIL;
+ }
+
++
++ /* if it decrypted okay, then things are good, this packet is
++ * well received, and we should change state.
++ */
++ rehash_state(st);
++
+ if(!ikev2_decode_peer_id(md, RESPONDER)) {
+ return STF_FAIL + INVALID_ID_INFORMATION;
+ }
+@@ -1784,10 +1794,13 @@ ikev2_parent_inI2outR2_tail(struct pluto_crypto_req_cont *pcrc
+ /* HDR out */
+ {
+ struct isakmp_hdr r_hdr = md->hdr;
++
++ r_hdr.isa_version = IKEv2_MAJOR_VERSION << ISA_MAJ_SHIFT | IKEv2_MINOR_VERSION;
+
+ r_hdr.isa_np = ISAKMP_NEXT_v2E;
+ r_hdr.isa_xchg = ISAKMP_v2_AUTH;
+ r_hdr.isa_flags = ISAKMP_FLAGS_R;
++ r_hdr.isa_msgid = htonl(md->msgid_received);
+ memcpy(r_hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
+ memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
+ if (!out_struct(&r_hdr, &isakmp_hdr_desc, &reply_stream, &md->rbody))
+@@ -1902,14 +1915,7 @@ ikev2_parent_inI2outR2_tail(struct pluto_crypto_req_cont *pcrc
+ if(np == ISAKMP_NEXT_v2SA) {
+ /* must have enough to build an CHILD_SA */
+ ret = ikev2_child_sa_respond(md, RESPONDER, &e_pbs_cipher);
+- if(ret > STF_FAIL) {
+- v2_notify_num = ret - STF_FAIL;
+- DBG(DBG_CONTROL,DBG_log("ikev2_child_sa_respond returned STF_FAIL with %s", enum_name(&ikev2_notify_names, v2_notify_num)))
+- np = ISAKMP_NEXT_NONE;
+- } else if(ret != STF_OK) {
+- DBG_log("ikev2_child_sa_respond returned %s", enum_name(&stfstatus_name, ret));
+- np = ISAKMP_NEXT_NONE;
+- }
++ if(ret != STF_OK) return ret;
+ }
+
+ ikev2_padup_pre_encrypt(md, &e_pbs_cipher);
+@@ -1944,6 +1950,7 @@ ikev2_parent_inI2outR2_tail(struct pluto_crypto_req_cont *pcrc
+
+ /* note: retransimission is driven by initiator */
+
++ ikev2_update_counters(md, response_sent);
+ /* if the child failed, delete its state here - we sent the packet */
+ /* PAUL */
+ return STF_OK;
+@@ -1966,6 +1973,8 @@ stf_status ikev2parent_inR2(struct msg_digest *md)
+ struct connection *c = st->st_connection;
+ unsigned char *idhash_in;
+ struct state *pst = st;
++ struct traffic_selector tsi[16], tsr[16];
++ unsigned int tsi_n=0, tsr_n=0;
+
+ if(st->st_clonedfrom != 0) {
+ pst = state_with_serialno(st->st_clonedfrom);
+@@ -2073,6 +2082,28 @@ stf_status ikev2parent_inR2(struct msg_digest *md)
+ */
+ change_state(pst, STATE_PARENT_I3);
+ c->newest_isakmp_sa = pst->st_serialno;
++
++ {
++ /*check for child sa related errors */
++ /* check for TS_UNACCEPTABLE */
++ struct payload_digest *p;
++
++ for(p = md->chain[ISAKMP_NEXT_v2N]; p != NULL; p = p->next)
++ {
++ if ( p->payload.v2n.isan_type == v2N_TS_UNACCEPTABLE ) {
++ /* we can proceed with successful parent SA */
++ if(st->st_clonedfrom != 0) {
++ delete_event(st);
++ pst = state_with_serialno(st->st_clonedfrom);
++ md->st = pst;
++ md->pst = pst;
++ delete_event(st);
++ delete_state(st);
++ }
++ return STF_OK;
++ }
++ }
++ }
+
+ /* authentication good, see if there is a child SA available */
+ if(md->chain[ISAKMP_NEXT_v2SA] == NULL
+@@ -2084,79 +2115,49 @@ stf_status ikev2parent_inR2(struct msg_digest *md)
+ /*
+ * Delete previous retransmission event.
+ */
+- delete_event(st);
++ if(st->st_clonedfrom != 0) {
++ pst = state_with_serialno(st->st_clonedfrom);
++ md->st = pst;
++ md->pst = pst;
++ delete_event(st);
++ delete_state(st);
++ }
+ return STF_OK;
+ }
+
+ {
+- int bestfit_n, bestfit_p;
+- unsigned int best_tsi_i , best_tsr_i;
+- bestfit_n = -1;
+- bestfit_p = -1;
+-
+- /* Check TSi/TSr http://tools.ietf.org/html/rfc5996#section-2.9 */
+- DBG(DBG_CONTROLMORE,DBG_log(" check narrowing - we are responding to I2"));
+-
+- struct payload_digest *const tsi_pd = md->chain[ISAKMP_NEXT_v2TSi];
+- struct payload_digest *const tsr_pd = md->chain[ISAKMP_NEXT_v2TSr];
+- struct traffic_selector tsi[16], tsr[16];
+- int tsc=0;
+-#if 0
+- bool instantiate = FALSE;
+- ip_subnet tsi_subnet, tsr_subnet;
+- const char *oops;
+-#endif
++ struct payload_digest *const tsi_pd = md->chain[ISAKMP_NEXT_v2TSi];
++ struct payload_digest *const tsr_pd = md->chain[ISAKMP_NEXT_v2TSr];
+
+- unsigned int tsi_n, tsr_n;
+- tsi_n = ikev2_parse_ts(tsi_pd, tsi, 16);
+- tsr_n = ikev2_parse_ts(tsr_pd, tsr, 16);
++ /* parse traffic selector */
+
+- DBG_log("Checking TSi(%d)/TSr(%d) selectors, looking for exact match", tsi_n,tsr_n);
+- {
+- struct spd_route *sra ;
+- sra = &c->spd;
+- int bfit_n=ikev2_evaluate_connection_fit(c,sra,INITIATOR,tsi,tsr,tsi_n, tsr_n);
+- if (bfit_n > bestfit_n)
+- {
+- DBG(DBG_CONTROLMORE, DBG_log("bfit_n=ikev2_evaluate_connection_fit found better fit c %s", c->name));
+- int bfit_p = ikev2_evaluate_connection_port_fit (c ,sra,INITIATOR,tsi,tsr,
+- tsi_n,tsr_n, &best_tsi_i, &best_tsr_i);
+- if (bfit_p > bestfit_p) {
+- DBG(DBG_CONTROLMORE, DBG_log("ikev2_evaluate_connection_port_fit found better fit c %s, tsi[%d],tsr[%d]"
+- , c->name, best_tsi_i, best_tsr_i));
+- bestfit_p = bfit_p;
+- bestfit_n = bfit_n;
+- }
+- }
+- else
+- DBG(DBG_CONTROLMORE, DBG_log("prefix range fit c %s c->name was rejected by port matching"
+- , c->name));
+- }
++ tsi_n = ikev2_parse_ts(tsi_pd, tsi, 16);
++ tsr_n = ikev2_parse_ts(tsr_pd, tsr, 16);
+
+- if ( ( bestfit_n > 0 ) && (bestfit_p > 0)) {
+- DBG(DBG_CONTROLMORE, DBG_log(("found an acceptable TSi/TSr Traffic Selector")));
+- memcpy (&st->st_ts_this , &tsi[best_tsi_i], sizeof(struct traffic_selector));
+- memcpy (&st->st_ts_that , &tsr[best_tsr_i], sizeof(struct traffic_selector));
+- ikev2_print_ts(&st->st_ts_this);
+- ikev2_print_ts(&st->st_ts_that);
+- }
+- else {
+- DBG(DBG_CONTROLMORE, DBG_log(("reject responder TSi/TSr Traffic Selector")));
+- // prevents parent from going to I3
+- return STF_FAIL + v2N_TS_UNACCEPTABLE;
+- }
+- } /* end of TS check block */
+-
+- {
+- v2_notification_t rn;
+- struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_v2SA];
++ /* verify if the received traffic selectors are
++ * really same/or a subset of what we sent
++ */
++ if(ikev2_verify_ts(tsi, tsr, tsi_n, tsr_n
++ , &st->st_ts_this, &st->st_ts_that
++ , md->role) == FALSE) {
++ /* mistmatch in received selectors */
++ /*only proceeding with parent SA*/
++ delete_event(st);
++ return STF_OK;
++ }
+
+- rn = ikev2_parse_child_sa_body(&sa_pd->pbs, &sa_pd->payload.v2sa,
+- NULL, st, FALSE);
++ }
+
+- if(rn != v2N_NOTHING_WRONG)
+- return STF_FAIL + rn;
+- }
++ {
++ v2_notification_t rn;
++ struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_v2SA];
++
++ rn = ikev2_parse_child_sa_body(&sa_pd->pbs, &sa_pd->payload.v2sa,
++ NULL, st, FALSE);
++
++ if(rn != v2N_NOTHING_WRONG)
++ return STF_FAIL + rn;
++ }
+
+ {
+ struct payload_digest *p;
+@@ -2196,21 +2197,108 @@ stf_status ikev2parent_inR2(struct msg_digest *md)
+
+ } /* notification block */
+
+-
+- ikev2_derive_child_keys(st, md->role);
++ {
++ /*storing received traffic selectors */
+
+- c->newest_ipsec_sa = st->st_serialno;
++ struct traffic_selector *tmp;
++ unsigned int i=0;
+
+- /* now install child SAs */
+- if(!install_ipsec_sa(st, TRUE))
+- return STF_FATAL;
+
+- /*
+- * Delete previous retransmission event.
+- */
+- delete_event(st);
++ ikev2_store_ts_instate(tsi, tsr, tsi_n, tsr_n, &st->st_ts_this, &st->st_ts_that);
+
+- return STF_OK;
++ for(i=0; i< tsi_n; i++) {
++
++ DBG(DBG_CONTROLMORE,
++ {
++ char lbi[ADDRTOT_BUF];
++ char hbi[ADDRTOT_BUF];
++ addrtot(&tsi[i].low, 0, lbi, sizeof(lbi));
++ addrtot(&tsi[i].high, 0, hbi, sizeof(hbi));
++
++ DBG_log("tsi=%s/%s, port=%d/%d, protocol=%d"
++ , lbi, hbi, tsi[i].startport, tsi[i].endport, tsi[i].ipprotoid);
++ }
++ );
++
++ }
++
++ for(i=0; i< tsr_n; i++) {
++
++ DBG(DBG_CONTROLMORE,
++ {
++ char lbi[ADDRTOT_BUF];
++ char hbi[ADDRTOT_BUF];
++ addrtot(&tsr[i].low, 0, lbi, sizeof(lbi));
++ addrtot(&tsr[i].high, 0, hbi, sizeof(hbi));
++
++ DBG_log("tsr=%s/%s, port=%d/%d, protocol=%d"
++ , lbi, hbi, tsr[i].startport, tsr[i].endport, tsr[i].ipprotoid);
++ }
++ );
++
++ }
++
++
++ tmp = &st->st_ts_this;
++
++ while(tmp!= NULL) {
++
++ DBG(DBG_CONTROLMORE,
++ {
++ char lbi[ADDRTOT_BUF];
++ char hbi[ADDRTOT_BUF];
++ addrtot(&tmp->low, 0, lbi, sizeof(lbi));
++ addrtot(&tmp->high, 0, hbi, sizeof(hbi));
++
++ DBG_log(" R2 this tsr=%s/%s, port=%d/%d, protocol=%d"
++ , lbi, hbi, tmp->startport, tmp->endport, tmp->ipprotoid);
++ }
++ );
++
++ tmp=tmp->next;
++ }
++
++ tmp = &st->st_ts_that;
++ while(tmp!= NULL) {
++
++ DBG(DBG_CONTROLMORE,
++ {
++ char lbi[ADDRTOT_BUF];
++ char hbi[ADDRTOT_BUF];
++ addrtot(&tmp->low, 0, lbi, sizeof(lbi));
++ addrtot(&tmp->high, 0, hbi, sizeof(hbi));
++
++ DBG_log(" R2 that tsr=%s/%s, port=%d/%d, protocol=%d"
++ , lbi, hbi, tmp->startport, tmp->endport, tmp->ipprotoid);
++ }
++ );
++
++ tmp=tmp->next;
++ }
++
++ if(!ikev2_perfect_match_ts(tsi, tsr, tsi_n, tsr_n, c, md->role)) {
++ c = ikev2_create_narrowed_con(c, &st->st_ts_this, &st->st_ts_that, md->role);
++ st->st_connection = c;
++ }
++
++ }
++
++ ikev2_derive_child_keys(st, md->role);
++
++ /* now install child SAs */
++ if(!install_ipsec_sa(st, TRUE))
++ return STF_FATAL;
++
++ st->st_childsa = c;
++ c->newest_ipsec_sa = st->st_serialno;
++ /*
++ * Delete previous retransmission event.
++ */
++ delete_event(st);
++ ikev2_update_counters(md, response_recd);
++
++ return STF_OK;
++
+ }
+
+ /*
+@@ -2317,7 +2405,7 @@ send_v2_notification(struct state *p1st, u_int16_t type
+ n_hdr.isa_np = ISAKMP_NEXT_v2N;
+ n_hdr.isa_flags &= ~ISAKMP_FLAGS_I;
+ n_hdr.isa_flags |= ISAKMP_FLAGS_R;
+-#warning check msgid code here
++
+ // PAUL: shouldn't we set n_hdr.isa_msgid = [htonl](p1st->st_msgid);
+ if (!out_struct(&n_hdr, &isakmp_hdr_desc, &reply, &rbody))
+ {
+@@ -2409,15 +2497,15 @@ stf_status process_informational_ikev2(struct msg_digest *md)
+ {
+ stf_status ret;
+
+- if(md->hdr.isa_flags & ISAKMP_FLAGS_I) {
++ if(!(md->hdr.isa_flags & ISAKMP_FLAGS_R)) {
+ DBG(DBG_CONTROLMORE
+- , DBG_log("received informational exchange request from INITIATOR"));
+- ret = ikev2_decrypt_msg(md, RESPONDER);
++ , DBG_log("received informational exchange request from %s", md->role == 1? "RESPONDER": "INITIATOR"));
++ ret = ikev2_decrypt_msg(md, md->role);
+ }
+ else {
+ DBG(DBG_CONTROLMORE
+- , DBG_log("received informational exchange request from RESPONDER"));
+- ret = ikev2_decrypt_msg(md, INITIATOR);
++ , DBG_log("received informational exchange response from %s", md->role == 1?"RESPONDER": "INITIATOR"));
++ ret = ikev2_decrypt_msg(md, md->role);
+ }
+
+ if(ret != STF_OK) return ret;
+@@ -2439,13 +2527,13 @@ stf_status process_informational_ikev2(struct msg_digest *md)
+ int ivsize;
+ unsigned char *encstart;
+
+- /* beginning of data going out */
+- authstart = reply_stream.cur;
+-
+ /* make sure HDR is at start of a clean buffer */
+ zero(reply_buffer);
+ init_pbs(&reply_stream, reply_buffer, sizeof(reply_buffer), "information exchange reply packet");
+
++ /* beginning of data going out */
++ authstart = reply_stream.cur;
++
+ /* HDR out */
+ {
+ struct isakmp_hdr r_hdr ;
+@@ -2645,7 +2733,7 @@ stf_status process_informational_ikev2(struct msg_digest *md)
+ close_output_pbs(&md->rbody);
+ close_output_pbs(&reply_stream);
+
+- ret = ikev2_encrypt_msg(md, RESPONDER,
++ ret = ikev2_encrypt_msg(md, md->role,
+ authstart,
+ iv, encstart, authloc,
+ &e_pbs, &e_pbs_cipher);
+@@ -2662,14 +2750,19 @@ stf_status process_informational_ikev2(struct msg_digest *md)
+ , "reply packet for informational exchange");
+
+ send_packet(st, __FUNCTION__, TRUE);
++ ikev2_update_counters(md, response_sent);
+ }
+
+ /* Now carry out the actualy task, we can not carry the actual task since
+ * we need to send informational responde using existig SAs
+ */
+
++ if(md->hdr.isa_flags & ISAKMP_FLAGS_R){
++ ikev2_update_counters(md, response_recd);
++ }
++
+ {
+- if(md->chain[ISAKMP_NEXT_v2D] && st->st_state != STATE_IKESA_DEL) {
++ if(md->chain[ISAKMP_NEXT_v2D]) {
+
+ for(p = md->chain[ISAKMP_NEXT_v2D]; p!=NULL; p = p->next) {
+ v2del = &p->payload.v2delete;
+@@ -2704,6 +2797,8 @@ stf_status process_informational_ikev2(struct msg_digest *md)
+ else
+ {
+ change_state(current_st, STATE_IKESA_DEL);
++ md->st = NULL;
++ md->pst = NULL;
+ }
+ delete_state(current_st);
+ current_st = next_st;
+@@ -2714,8 +2809,6 @@ stf_status process_informational_ikev2(struct msg_digest *md)
+ case PROTO_IPSEC_AH:
+ case PROTO_IPSEC_ESP:
+ {
+- //pb_stream del_pbs;
+- struct ikev2_delete;
+ u_int16_t i;
+ u_char *spi;
+
+@@ -2796,6 +2889,8 @@ stf_status process_informational_ikev2(struct msg_digest *md)
+ else
+ {
+ change_state(current_st, STATE_IKESA_DEL);
++ md->st = NULL;
++ md->pst = NULL;
+ }
+ delete_state(current_st);
+ current_st = next_st;
+@@ -2853,12 +2948,14 @@ void ikev2_delete_out(struct state *st)
+ md.st = st;
+ md.pst= pst;
+ /* beginning of data going out */
+- authstart = reply_stream.cur;
+
+ /* make sure HDR is at start of a clean buffer */
+ zero(reply_buffer);
+ init_pbs(&reply_stream, reply_buffer, sizeof(reply_buffer), "information exchange request packet");
+
++ /* beginning of data going out */
++ authstart = reply_stream.cur;
++
+ /* HDR out */
+ {
+ struct isakmp_hdr r_hdr ;
+@@ -2868,7 +2965,7 @@ void ikev2_delete_out(struct state *st)
+ memcpy(r_hdr.isa_icookie, pst->st_icookie, COOKIE_SIZE);
+ r_hdr.isa_xchg = ISAKMP_v2_INFORMATIONAL;
+ r_hdr.isa_np = ISAKMP_NEXT_v2E;
+- r_hdr.isa_msgid = htonl(pst->st_msgid_nextuse);
++ r_hdr.isa_msgid = htonl(pst->st_msgid_last_localreq == INVALID_MSGID? 0 : pst->st_msgid_last_localreq + 1);
+
+ /*set initiator bit if we are initiator*/
+ if(pst->st_state == STATE_PARENT_I2 || pst->st_state == STATE_PARENT_I3) {
+@@ -2879,8 +2976,6 @@ void ikev2_delete_out(struct state *st)
+ role = RESPONDER;
+ }
+
+- //r_hdr.isa_flags |= ISAKMP_FLAGS_R;
+-
+ if (!out_struct(&r_hdr, &isakmp_hdr_desc, &reply_stream, &rbody))
+ {
+ openswan_log("error initializing hdr for informational message");
+@@ -2916,9 +3011,6 @@ void ikev2_delete_out(struct state *st)
+ {
+ pb_stream del_pbs;
+ struct ikev2_delete v2del_tmp;
+- //u_int16_t i, j=0;
+- //u_char *spi;
+- //char spi_buf[1024];
+
+ zero(&v2del_tmp);
+ v2del_tmp.isad_np = ISAKMP_NEXT_NONE;
+@@ -2984,7 +3076,7 @@ void ikev2_delete_out(struct state *st)
+ send_packet(pst, __FUNCTION__, TRUE);
+
+ /* update state */
+- ikev2_update_counters(&md);
++ ikev2_update_counters(&md, req_sent);
+
+ }
+
+diff --git a/programs/pluto/kernel.c b/programs/pluto/kernel.c
+index 70d49ed..c8c8db8 100644
+--- a/programs/pluto/kernel.c
++++ b/programs/pluto/kernel.c
+@@ -2028,6 +2028,31 @@ setup_half_ipsec_sa(struct state *st, bool inbound)
+ , st->st_connection->policy_label
+ #endif
+ );
++
++ if(st->st_ikev2) {
++ struct spd_route *sr = &c->spd;
++ for(sr = sr->next; sr != NULL; sr = sr->next) {
++
++ /* MCR - should be passed a spd_eroute structure here */
++ (void) raw_eroute(&sr->that.host_addr /* this_host */
++ , &sr->that.client /* this_client */
++ , &sr->this.host_addr /* that_host */
++ , &sr->this.client /* that_client */
++ , inner_spi /* spi */
++ , proto /* proto */
++ , sr->this.protocol /* transport_proto */
++ , esatype /* esatype */
++ , proto_info /* " */
++ , 0 /* lifetime */
++ , ERO_ADD_INBOUND /* op */
++ , "add inbound" /* opname */
++#ifdef HAVE_LABELED_IPSEC
++ , st->st_connection->policy_label
++#endif
++ );
++ }
++ }
++
+ }
+ }
+
+@@ -2103,6 +2128,7 @@ teardown_half_ipsec_sa(struct state *st, bool inbound)
+ * first one found. It may or may not be the only one.
+ */
+ struct connection *c = st->st_connection;
++ struct spd_route *sr;
+ struct {
+ unsigned proto;
+ struct ipsec_proto_info *info;
+@@ -2128,6 +2154,30 @@ teardown_half_ipsec_sa(struct state *st, bool inbound)
+ );
+ }
+
++ if(st->st_ikev2) {
++ for(sr = &c->spd.next; sr; sr =sr->next) {
++ if (kernel_ops->inbound_eroute && inbound
++ && sr->eroute_owner == SOS_NOBODY)
++ {
++ (void) raw_eroute(&sr->that.host_addr, &sr->that.client
++ , &sr->this.host_addr, &sr->this.client
++ , 256
++ , IPSEC_PROTO_ANY
++ , sr->this.protocol
++ , ET_UNSPEC
++ , null_proto_info, 0
++ , ERO_DEL_INBOUND, "delete inbound"
++#ifdef HAVE_LABELED_IPSEC
++ , c->policy_label
++#endif
++ );
++ }
++ }
++ }
++
++
++
++
+ if (!kernel_ops->grp_sa)
+ {
+ if (st->st_ah.present)
+diff --git a/programs/pluto/state.c b/programs/pluto/state.c
+index bc89489..47dd189 100644
+--- a/programs/pluto/state.c
++++ b/programs/pluto/state.c
+@@ -347,6 +347,19 @@ release_whack(struct state *st)
+ close_any(st->st_whack_sock);
+ }
+
++/* freeing allocated traffic selectors */
++static void delete_ts(struct traffic_selector *ts) {
++ struct traffic_selector *tmp;
++
++ /*first one is not malloced so skiping that*/
++ ts = ts-> next;
++ while(ts!=NULL) {
++ tmp = ts->next;
++ pfreeany(ts);
++ ts = tmp;
++ }
++}
++
+ /* delete a state object */
+ void
+ delete_state(struct state *st)
+@@ -354,8 +367,60 @@ delete_state(struct state *st)
+ struct connection *const c = st->st_connection;
+ struct state *old_cur_state = cur_state == st? NULL : cur_state;
+
+- DBG(DBG_CONTROL, DBG_log("deleting state #%lu", st->st_serialno));
++ if(st->st_ikev2)
++ {
++ /* child sa*/
++ if(st->st_clonedfrom != 0)
++ {
++ DBG(DBG_CONTROL, DBG_log("received request to delete child state"));
++ if(st->st_state == STATE_CHILDSA_DEL) {
++ DBG(DBG_CONTROL, DBG_log("now deleting the child state"));
++ }
++ else
++ {
++ /* Only send request if child sa is established
++ * otherwise continue with deletion
++ */
++ if(IS_CHILD_SA_ESTABLISHED(st))
++ {
++ DBG(DBG_CONTROL, DBG_log("sending Child SA delete equest"));
++ //change_state(st, STATE_CHILDSA_DEL);
++ send_delete(st);
++ change_state(st, STATE_CHILDSA_DEL);
++ /* actual deletion when we receive peer response*/
++ goto delete_state_end;
++ }
++ }
++ }
++ else
++ {
++ DBG(DBG_CONTROL, DBG_log("received request to delete IKE parent state"));
++ /* parent sa */
++ if(st->st_state == STATE_IKESA_DEL)
++ {
++ DBG(DBG_CONTROL, DBG_log("now deleting the IKE (or parent) state"));
++ }
++ else
++ {
++ /* Another check to verify if a secured
++ * INFORMATIONAL exchange can be sent or not
++ */
++ if(st->st_skey_ei.ptr && st->st_skey_ai.ptr
++ && st->st_skey_er.ptr && st->st_skey_ar.ptr)
++ {
++ DBG(DBG_CONTROL, DBG_log("sending IKE SA delete request"));
++ //change_state(st, STATE_IKESA_DEL);
++ send_delete(st);
++ change_state(st, STATE_IKESA_DEL);
++ /* actual deletion when we receive peer response*/
++ goto delete_state_end;
++ }
++ }
++
++ }
++ }
+
++ DBG(DBG_CONTROL, DBG_log("deleting state #%lu", st->st_serialno));
+
+ /* If DPD is enabled on this state object, clear any pending events */
+ if(st->st_dpd_event != NULL)
+@@ -455,6 +520,10 @@ delete_state(struct state *st)
+ pfreeany(st->st_sec_chunk.ptr);
+ }
+
++ /*free selectors if any */
++ delete_ts(&st->st_ts_this);
++ delete_ts(&st->st_ts_that);
++
+ freeanychunk(st->st_firstpacket_me);
+ freeanychunk(st->st_firstpacket_him);
+ freeanychunk(st->st_tpacket);
+@@ -506,6 +575,9 @@ delete_state(struct state *st)
+ pfreeany(st->sec_ctx);
+ #endif
+ pfree(st);
++
++delete_state_end:;
++
+ }
+
+ /*
+@@ -596,6 +668,9 @@ static void delete_state_function(struct state *this
+ , enum_show(&state_names, this->st_state));
+
+ if(this->st_event != NULL) delete_event(this);
++ if(this->st_ikev2) {
++ this->st_state = this->st_clonedfrom ? STATE_CHILDSA_DEL : STATE_IKESA_DEL;
++ }
+ delete_state(this);
+ }
+
+diff --git a/programs/pluto/state.h b/programs/pluto/state.h
+index 80be846..5104adf 100644
+--- a/programs/pluto/state.h
++++ b/programs/pluto/state.h
+@@ -165,6 +165,7 @@ struct traffic_selector {
+ u_int16_t endport;
+ ip_address low;
+ ip_address high;
++ struct traffic_selector *next;
+ };
+
+ #ifdef HAVE_LABELED_IPSEC
+@@ -250,12 +251,13 @@ struct state
+ struct msgid_list *st_used_msgids; /* used-up msgids */
+
+ /* IKEv2 things */
+- /* message ID sequence for things we send (as initiator) */
+- msgid_t st_msgid_lastack; /* last one peer acknowledged */
+- msgid_t st_msgid_nextuse; /* next one to use */
++ /* message ID sequence for things we send (as request) */
++ msgid_t st_msgid_last_localreq; /* last one sent as request by us */
++ msgid_t st_msgid_last_localreq_ack; /* last one sent acked by peer */
+
+- /* message ID sequence for things we receive (as responder) */
+- msgid_t st_msgid_lastrecv; /* last one peer sent */
++
++ /* message ID sequence for things we receive (as response) */
++ msgid_t st_msgid_last_remotereq; /* last remote request sent by peer */
+
+
+ /* symmetric stuff */
diff --git a/openswan-ipsec-help-524146-509318.patch b/openswan-ipsec-help-524146-509318.patch
index a4ed01d..102b400 100644
--- a/openswan-ipsec-help-524146-509318.patch
+++ b/openswan-ipsec-help-524146-509318.patch
@@ -1,6 +1,13 @@
-diff -urNp openswan-2.6.38-patched/programs/ipsec/ipsec.in openswan-2.6.38-current/programs/ipsec/ipsec.in
---- openswan-2.6.38-patched/programs/ipsec/ipsec.in 2012-05-14 15:17:33.563272378 -0400
-+++ openswan-2.6.38-current/programs/ipsec/ipsec.in 2012-05-14 15:20:50.952267555 -0400
+From 1bdb95de068810c49d35d3b5681b20eccaf9a40f Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Thu, 29 Sep 2011 16:18:16 -0400
+Subject: openswan-ipsec-help-524146-509318.patch
+
+
+diff --git a/programs/ipsec/ipsec.in b/programs/ipsec/ipsec.in
+index b8e9d4e..4f73ab1 100755
+--- a/programs/ipsec/ipsec.in
++++ b/programs/ipsec/ipsec.in
@@ -80,9 +80,9 @@ case "$1" in
--help)
echo "Usage: ipsec command argument ..."
diff --git a/openswan-labeled-ipsec.patch b/openswan-labeled-ipsec.patch
new file mode 100644
index 0000000..a6771c0
--- /dev/null
+++ b/openswan-labeled-ipsec.patch
@@ -0,0 +1,115 @@
+From 41aa84182b0291533745da59beb26bcce80d56a8 Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Fri, 9 Mar 2012 16:50:05 -0500
+Subject: =?UTF-8?q?Changes=20related=20to=20bz#703985=20not=20merged=20upstr?=
+ =?UTF-8?q?eam.=20Also=20this=20commit=20has=0Asome=20misc=20(not=20necessar?=
+ =?UTF-8?q?y)=20labeled=20ipsec=20changes.?=
+
+
+diff --git a/lib/libipsecconf/confread.c b/lib/libipsecconf/confread.c
+index 6070f3f..4fc6096 100644
+--- a/lib/libipsecconf/confread.c
++++ b/lib/libipsecconf/confread.c
+@@ -1356,6 +1356,9 @@ static void confread_free_conn(struct starter_conn *conn)
+
+ FREE_STR(conn->connalias);
+ FREE_STR(conn->name);
++//#ifdef HAVE_LABELED_IPSEC
++// FREE_STR(conn->policy_label);
++//#endif
+
+ #ifdef ALG_PATCH
+ FREE_STR(conn->esp);
+diff --git a/lib/libipsecconf/oeconns.c b/lib/libipsecconf/oeconns.c
+index 72e1a84..c94da0e 100644
+--- a/lib/libipsecconf/oeconns.c
++++ b/lib/libipsecconf/oeconns.c
+@@ -524,6 +524,9 @@ void add_any_oeconns(struct starter_config *cfg,
+ conn->right= tconn->right;
+ conn->esp = tconn->esp;
+ conn->ike = tconn->ike;
++//#ifdef HAVE_LABELED_IPSEC
++// conn->policy_label = tconn->policy_label;
++//#endif
+ conn->desired_state = tconn->desired_state;
+ conn->policy = tconn->policy;
+ conn->state = STATE_LOADED;
+diff --git a/lib/libipsecconf/starterwhack.c b/lib/libipsecconf/starterwhack.c
+index d6ff9f7..73aa6f0 100644
+--- a/lib/libipsecconf/starterwhack.c
++++ b/lib/libipsecconf/starterwhack.c
+@@ -547,12 +547,15 @@ static int starter_whack_basic_add_conn(struct starter_config *cfg
+ if(conn->options_set[KBF_LOOPBACK]) {
+ msg.loopback=conn->options[KBF_LOOPBACK];
+ }
++ starter_log(LOG_LEVEL_INFO, "conn: \"%s\" loopback=%d", conn->name, msg.loopback);
+
+ if(conn->options_set[KBF_LABELED_IPSEC]) {
+ msg.labeled_ipsec=conn->options[KBF_LABELED_IPSEC];
+ }
++ starter_log(LOG_LEVEL_INFO, "conn: \"%s\" labeled_ipsec=%d", conn->name, msg.labeled_ipsec);
+
+ msg.policy_label = conn->policy_label;
++ starter_log(LOG_LEVEL_INFO, "conn: \"%s\" policy_label=%d", conn->name, msg.policy_label);
+ #endif
+
+ set_whack_end(cfg, "left", &msg.left, &conn->left);
+diff --git a/programs/pluto/initiate.c b/programs/pluto/initiate.c
+index 658887c..dd186e6 100644
+--- a/programs/pluto/initiate.c
++++ b/programs/pluto/initiate.c
+@@ -776,19 +776,17 @@ initiate_ondemand_body(struct find_oppo_bundle *b
+
+
+ #ifdef HAVE_LABELED_IPSEC
+- char sec_ctx_value[256];
++ char sec_ctx_value[MAX_SECCTX_LEN];
+ memset(sec_ctx_value, 0, sizeof(sec_ctx_value));
+ if(uctx != NULL) {
+ memcpy(sec_ctx_value, uctx->sec_ctx_value, uctx->ctx_len);
+ }
+- snprintf(demandbuf, 256, "initiate on demand from %s:%d to %s:%d proto=%d state: %s because: %s with security context %s"
+- , ours, ourport, his, hisport, b->transport_proto
+- , oppo_step_name[b->step], b->want, sec_ctx_value);
+-#else
++ DBG(DBG_CONTROLMORE, DBG_log("received security label string: %s", sec_ctx_value));
++#endif
++
+ snprintf(demandbuf, 256, "initiate on demand from %s:%d to %s:%d proto=%d state: %s because: %s"
+ , ours, ourport, his, hisport, b->transport_proto
+ , oppo_step_name[b->step], b->want);
+-#endif
+
+ if(DBGP(DBG_OPPOINFO)) {
+ openswan_log("%s", demandbuf);
+diff --git a/programs/pluto/spdb_v1_struct.c b/programs/pluto/spdb_v1_struct.c
+index 77427b2..97faf35 100644
+--- a/programs/pluto/spdb_v1_struct.c
++++ b/programs/pluto/spdb_v1_struct.c
+@@ -105,11 +105,22 @@ parse_secctx_attr (pb_stream *pbs, struct state *st)
+ return FALSE;
+ }
+
+- /* reading security label*/
+- memcpy(sec_ctx_value, pbs->cur, pbs_left(pbs) <= MAX_SECCTX_LEN ? pbs_left(pbs) : MAX_SECCTX_LEN);
+- i = pbs_left(pbs) <= MAX_SECCTX_LEN ? pbs_left(pbs) : MAX_SECCTX_LEN;
++ /*do not process security labels longer than MAX_SECCTX_LEN*/
++ if(pbs_left(pbs) > MAX_SECCTX_LEN) {
++ DBG(DBG_PARSING, DBG_log("received security ctx longer than MAX_SECCTX_LEN which is not supported"));
++ return FALSE;
++ }
+
+- /* checking if the received security label contains \0 */
++ /* reading security label*/
++ //memcpy(sec_ctx_value, pbs->cur, pbs_left(pbs) <= MAX_SECCTX_LEN ? pbs_left(pbs) : MAX_SECCTX_LEN);
++ //i = pbs_left(pbs) <= MAX_SECCTX_LEN ? pbs_left(pbs) : MAX_SECCTX_LEN;
++ memcpy(sec_ctx_value, pbs->cur, pbs_left(pbs));
++ i = pbs_left(pbs);
++
++ /* checking if the received security label contains \0,
++ * We expect received label to have '\0', however to be
++ * compliant with implementations that dont send \0
++ * we can include \0 if there is space left in the buffer.*/
+ if( sec_ctx_value[i-1] != '\0') {
+ /*check if we have space left and then append \0*/
+ if (i < MAX_SECCTX_LEN) {
diff --git a/openswan-updown-netkey.patch b/openswan-updown-netkey.patch
new file mode 100644
index 0000000..74dd113
--- /dev/null
+++ b/openswan-updown-netkey.patch
@@ -0,0 +1,83 @@
+From 4ed4ff4391a100ba8bee37cd50341accbe4aca9f Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Tue, 7 Aug 2012 13:28:33 -0400
+Subject: =?UTF-8?q?Fixes=20to=20interop=20issues=20(related=20to=20updating/?=
+ =?UTF-8?q?rempoving=20local=20interface=20with=0Aremote=20ip=20address=20an?=
+ =?UTF-8?q?d=20removing=20local=20routes)=20between=20cisco=20ASA=20and=20op?=
+ =?UTF-8?q?enswan.?=
+
+
+diff --git a/programs/_updown.netkey/_updown.netkey.in b/programs/_updown.netkey/_updown.netkey.in
+index bb182bf..155750e 100644
+--- a/programs/_updown.netkey/_updown.netkey.in
++++ b/programs/_updown.netkey/_updown.netkey.in
+@@ -188,6 +188,14 @@ downroute() {
+ ip route flush cache
+ }
+
++downrule() {
++ if [ -n "$PLUTO_MY_SOURCEIP" ]
++ then
++ doroute del
++ ip route flush cache
++ fi
++}
++
+ updateresolvconf() {
+ if [ -n "$PLUTO_CISCO_DNS_INFO" ]; then
+ if [ -n "`pidof unbound`" -a -n "$PLUTO_CISCO_DOMAIN_INFO" ]; then
+@@ -316,7 +324,12 @@ addsource() {
+ st=0
+ # check if given sourceip is local and add as alias if not
+ if ! ip -o route get ${PLUTO_MY_SOURCEIP%/*} | grep -q ^local; then
++
++ if [ -z "$PLUTO_IS_PEER_CISCO" -o "$PLUTO_IS_PEER_CISCO" = 0 ]; then
+ it="ip addr add ${PLUTO_MY_SOURCEIP%/*}/32 dev ${PLUTO_INTERFACE%:*}"
++ else
++ it="ip addr add ${PLUTO_MY_SOURCEIP%/*}/${PLUTO_PEER_CLIENT##*/} dev ${PLUTO_INTERFACE%:*}"
++ fi
+ oops="`eval $it 2>&1`"
+ st=$?
+ if [ " $oops" = " " -a " $st" != " 0" ]; then
+@@ -341,15 +354,7 @@ delsource() {
+ st=0
+ # check if given sourceip is local and add as alias if not
+ if ip -o route get ${PLUTO_MY_SOURCEIP%/*} | grep -q ^local; then
+- #it="ip addr del ${PLUTO_MY_SOURCEIP%/*}/32 label ${PLUTO_INTERFACE%:*}:1 dev ${PLUTO_INTERFACE%:*}"
+-
+- saddr=${PLUTO_MY_SOURCEIP%/*}/32
+- if test "${PLUTO_PEER_CLIENT##*/}" != 32
+- then
+- saddr=${PLUTO_MY_SOURCEIP%/*}/"${PLUTO_PEER_CLIENT##*/}"
+- fi
+-
+- it="ip addr del ${saddr} dev ${PLUTO_INTERFACE%:*}"
++ it="ip addr del ${PLUTO_MY_SOURCEIP%/*}/${PLUTO_PEER_CLIENT##*/} dev ${PLUTO_INTERFACE%:*}"
+
+ oops="`eval $it 2>&1`"
+ st=$?
+@@ -365,7 +370,7 @@ delsource() {
+ ;;
+ esac
+ if [ " $oops" != " " -o " $st" != " 0" ]; then
+- echo "$0: addsource \`$it' failed ($oops)" >&2
++ echo "$0: delsource \`$it' failed ($oops)" >&2
+ fi
+ fi
+ return $st
+@@ -457,6 +462,7 @@ case "$PLUTO_VERB" in
+ ;;
+ down-host)
+ # connection to me going down
++ downrule
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+ up-client)
+@@ -465,6 +471,7 @@ case "$PLUTO_VERB" in
+ ;;
+ down-client)
+ # connection to my client subnet going down
++ downrule
+ # If you are doing a custom version, firewall commands go here.
+ ;;
+ updateresolvconf-host|updateresolvconf-client)
diff --git a/openswan.spec b/openswan.spec
index a255f4a..f0362bc 100644
--- a/openswan.spec
+++ b/openswan.spec
@@ -10,7 +10,7 @@ Summary: IPSEC implementation with IKEv1 and IKEv2 keying protocols
Name: openswan
Version: 2.6.38
-Release: 2%{?dist}
+Release: 3%{?dist}
License: GPLv2+
Url: http://www.openswan.org/
Source: openswan-%{version}.tar.gz
@@ -20,7 +20,17 @@ Source3: README.x509
Patch1: openswan-2.6-relpath.patch
Patch2: openswan-ipsec-help-524146-509318.patch
-Patch3: openswan-cisco-issues.patch
+Patch3: openswan-cisco-aggr-mode.patch
+Patch4: openswan-ikev2.patch
+Patch5: reading-password-from-a-file-when-creating-keys.patch
+Patch6: rhbz-609343.patch
+Patch7: openswan-labeled-ipsec.patch
+Patch8: openswan-ikev1-ikev2-sha256.patch
+Patch9: openswan-ikev1-ikev2-sha384-512.patch
+Patch10: openswan-ikev1-aes-gcm-esp-fixes.patch
+Patch11: rhbz-831676.patch
+Patch12: rhbz-841325.patch
+Patch13: openswan-updown-netkey.patch
Group: System Environment/Daemons
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
@@ -85,6 +95,16 @@ install -m 644 %{SOURCE3} docs/README.x509
%patch1 -p1 -b .relpath
%patch2 -p1
%patch3 -p1
+%patch4 -p1
+%patch5 -p1
+%patch6 -p1
+%patch7 -p1
+%patch8 -p1
+%patch9 -p1
+%patch10 -p1
+%patch11 -p1
+%patch12 -p1
+%patch13 -p1
%build
@@ -209,6 +229,18 @@ fi
chkconfig --add ipsec || :
%changelog
+* Tue Aug 7 2012 Avesh Agarwal <avagarwa at redhat.com> - 2.6.38-3
+- Ikev2 changes from rhel6 to fedora
+- Sha256 changes from rhel6 to fedora
+- Fixed 384/512 changes from rhel6 to fedora
+- Ported cisco-openswan interop changes in aggresive/main mode
+- Labeld-ipsec fixes
+- aes-gcm fixes in ikev1 mode
+- updown netkey script changes related to updating/removing
+ interface ip address and routes
+- Fixes related to rhbz 609343
+- Fixes related to rhbz 831676
+
* Fri Jul 20 2012 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 2.6.38-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
diff --git a/reading-password-from-a-file-when-creating-keys.patch b/reading-password-from-a-file-when-creating-keys.patch
new file mode 100644
index 0000000..6bfe7c8
--- /dev/null
+++ b/reading-password-from-a-file-when-creating-keys.patch
@@ -0,0 +1,19 @@
+From bd631c2947f1e9aefd77c6d9fb92230f4c0f5864 Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Fri, 30 Sep 2011 16:43:39 -0400
+Subject: Reading password from a file when creating keys.
+
+
+diff --git a/programs/rsasigkey/rsasigkey.c b/programs/rsasigkey/rsasigkey.c
+index 94b77d6..2dd7e6b 100644
+--- a/programs/rsasigkey/rsasigkey.c
++++ b/programs/rsasigkey/rsasigkey.c
+@@ -564,7 +564,7 @@ rsasigkey(int nbits, char *configdir, char *password)
+ mpz_init(n);
+ mpz_init(e);
+
+- pwdata.source = password ? PW_PLAINTEXT : PW_NONE;
++ pwdata.source = password ? (strcmp(password, "/etc/ipsec.d/nsspassword")? PW_PLAINTEXT: PW_FROMFILE) : PW_NONE;
+ pwdata.data = password ? password : NULL;
+
+ do {
diff --git a/rhbz-609343.patch b/rhbz-609343.patch
new file mode 100644
index 0000000..1d14e31
--- /dev/null
+++ b/rhbz-609343.patch
@@ -0,0 +1,32 @@
+From 0e88f1f2b7959c26a2c05ddd2b756c8b106124fe Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Fri, 21 Oct 2011 16:33:37 -0400
+Subject: rhbz#609343: pluto crashes when removing logical interface
+
+
+diff --git a/programs/pluto/hostpair.c b/programs/pluto/hostpair.c
+index 4d13e29..1c0bf68 100644
+--- a/programs/pluto/hostpair.c
++++ b/programs/pluto/hostpair.c
+@@ -299,7 +299,8 @@ release_dead_interfaces(void)
+ * move it to the unoriented_connections list.
+ */
+ passert(p == *pp);
+-
++
++ terminate_connection(p->name);
+ p->interface = NULL;
+
+ *pp = p->hp_next; /* advance *pp */
+diff --git a/programs/pluto/initiate.c b/programs/pluto/initiate.c
+index 94ce4f4..658887c 100644
+--- a/programs/pluto/initiate.c
++++ b/programs/pluto/initiate.c
+@@ -133,6 +133,7 @@ orient(struct connection *c)
+ else
+ loglog(RC_LOG_SERIOUS, "two interfaces match \"%s\" (%s, %s)"
+ , c->name, c->interface->ip_dev->id_rname, p->ip_dev->id_rname);
++ terminate_connection(c->name);
+ c->interface = NULL; /* withdraw orientation */
+ return FALSE;
+ }
diff --git a/rhbz-831676.patch b/rhbz-831676.patch
new file mode 100644
index 0000000..782bec6
--- /dev/null
+++ b/rhbz-831676.patch
@@ -0,0 +1,107 @@
+From 863e5dbb482fb82f035c3e17f7d5983c4bc72c63 Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Fri, 3 Aug 2012 14:53:16 -0400
+Subject: rhbz #831676
+
+Openswan does not pass traffic selectors information in transport mode.
+These fixes avoids loopback (same addresses scenarios).
+
+diff --git a/programs/pluto/kernel.c b/programs/pluto/kernel.c
+index 9924078..eb539bf 100644
+--- a/programs/pluto/kernel.c
++++ b/programs/pluto/kernel.c
+@@ -1438,6 +1438,7 @@ setup_half_ipsec_sa(struct state *st, bool inbound)
+ said_next->dst = &dst.addr;
+ said_next->src_client = &src_client;
+ said_next->dst_client = &dst_client;
++ said_next->transport_proto = c->spd.this.protocol;
+ said_next->spi = ipip_spi;
+ said_next->esatype = ET_IPIP;
+ said_next->text_said = text_said;
+@@ -1530,6 +1531,7 @@ setup_half_ipsec_sa(struct state *st, bool inbound)
+ said_next->dst = &dst.addr;
+ said_next->src_client = &src_client;
+ said_next->dst_client = &dst_client;
++ said_next->transport_proto = c->spd.this.protocol;
+ said_next->spi = ipcomp_spi;
+ said_next->esatype = ET_IPCOMP;
+ said_next->encalg = compalg;
+@@ -1742,6 +1744,7 @@ setup_half_ipsec_sa(struct state *st, bool inbound)
+ said_next->dst = &dst.addr;
+ said_next->src_client = &src_client;
+ said_next->dst_client = &dst_client;
++ said_next->transport_proto = c->spd.this.protocol;
+ said_next->spi = esp_spi;
+ said_next->esatype = ET_ESP;
+ said_next->replay_window = kernel_ops->replay_window;
+@@ -1900,6 +1903,7 @@ setup_half_ipsec_sa(struct state *st, bool inbound)
+ said_next->dst = &dst.addr;
+ said_next->src_client = &src_client;
+ said_next->dst_client = &dst_client;
++ said_next->transport_proto = c->spd.this.protocol;
+ said_next->spi = ah_spi;
+ said_next->esatype = ET_AH;
+ said_next->replay_window = kernel_ops->replay_window;
+diff --git a/programs/pluto/kernel.h b/programs/pluto/kernel.h
+index 772ba14..b843682 100644
+--- a/programs/pluto/kernel.h
++++ b/programs/pluto/kernel.h
+@@ -79,6 +79,7 @@ struct kernel_sa {
+
+ ipsec_spi_t spi;
+ unsigned proto;
++ unsigned int transport_proto;
+ enum eroute_type esatype;
+ unsigned replay_window;
+ unsigned reqid;
+diff --git a/programs/pluto/kernel_netlink.c b/programs/pluto/kernel_netlink.c
+index 895607c..351b0eb 100644
+--- a/programs/pluto/kernel_netlink.c
++++ b/programs/pluto/kernel_netlink.c
+@@ -818,6 +818,46 @@ netlink_add_sa(struct kernel_sa *sa, bool replace)
+ else
+ {
+ req.p.mode = XFRM_MODE_TRANSPORT;
++
++ if(!sameaddr(sa->src, sa->dst)) {
++ req.p.sel.sport = portof(&sa->src_client->addr);
++ req.p.sel.dport = portof(&sa->dst_client->addr);
++
++ /* As per RFC 4301/5996, icmp type is put in the most significant 8 bits
++ * and icmp code is in the least significant 8 bits of port field.
++ * Although Openswan does not have any configuration options for
++ * icmp type/code values, it is possible to specify icmp type and code
++ * using protoport option. For example, icmp echo request (type 8/code 0)
++ * needs to be encoded as 0x0800 in the port field and can be specified
++ * as left/rightprotoport=icmp/2048. Now with NETKEY, icmp type and code
++ * need to be passed as source and destination ports, respectively.
++ * therefore, this code extracts upper 8 bits and lower 8 bits and puts
++ * into source and destination ports before passing to NETKEY. */
++
++
++ if( 1 == sa->transport_proto /*icmp*/ || 58 == sa->transport_proto /*ipv6-icmp*/) {
++
++ u_int16_t icmp_type;
++ u_int16_t icmp_code;
++
++ icmp_type = ntohs(req.p.sel.sport) >> 8;
++ icmp_code = ntohs(req.p.sel.sport) & 0xFF;
++
++ req.p.sel.sport = htons(icmp_type);
++ req.p.sel.dport = htons(icmp_code);
++
++ }
++
++ req.p.sel.sport_mask = (req.p.sel.sport) ? ~0:0;
++ req.p.sel.dport_mask = (req.p.sel.dport) ? ~0:0;
++ ip2xfrm(&sa->src_client->addr, &req.p.sel.saddr);
++ ip2xfrm(&sa->dst_client->addr, &req.p.sel.daddr);
++ req.p.sel.prefixlen_s = sa->src_client->maskbits;
++ req.p.sel.prefixlen_d = sa->dst_client->maskbits;
++ req.p.sel.proto = sa->transport_proto;
++ req.p.sel.family = sa->src_client->addr.u.v4.sin_family;
++ }
++
+ }
+
+ req.p.replay_window = sa->replay_window > 32 ? 32 : sa->replay_window;
diff --git a/rhbz-841325.patch b/rhbz-841325.patch
new file mode 100644
index 0000000..23d03ce
--- /dev/null
+++ b/rhbz-841325.patch
@@ -0,0 +1,56 @@
+From e1280ce2abf5d8217b0690874fd9e5298fe37bca Mon Sep 17 00:00:00 2001
+From: Avesh Agarwal <avagarwa at redhat.com>
+Date: Tue, 7 Aug 2012 12:53:58 -0400
+Subject: rhbz #841325
+
+Fixes to interop issues between cisco ASA and openswan in main mode.
+These fixes prevents xauth/modecfg negotiation during IKE rekey in main mode.
+
+diff --git a/programs/pluto/ikev1_main.c b/programs/pluto/ikev1_main.c
+index cd4be12..9c1e660 100644
+--- a/programs/pluto/ikev1_main.c
++++ b/programs/pluto/ikev1_main.c
+@@ -2231,6 +2231,21 @@ main_inI3_outR3_tail(struct msg_digest *md
+ st->st_ph1_iv_len = st->st_new_iv_len;
+ set_ph1_iv(st, st->st_new_iv);
+
++ /* It seems as per Cisco implementation, XAUTH and MODECFG
++ * are not supposed to be performed again during rekey */
++ if(st->st_connection->newest_isakmp_sa != SOS_NOBODY &&
++ st->st_connection->spd.this.xauth_client) {
++ DBG(DBG_CONTROL, DBG_log("Skipping XAUTH for rekey for Cisco Peer compatibility."));
++ st->hidden_variables.st_xauth_client_done = TRUE;
++ st->st_oakley.xauth = 0;
++
++ if(st->st_connection->spd.this.modecfg_client) {
++ DBG(DBG_CONTROL, DBG_log("Skipping ModeCFG for rekey for Cisco Peer compatibility."));
++ st->hidden_variables.st_modecfg_vars_set = TRUE;
++ st->hidden_variables.st_modecfg_started = TRUE;
++ }
++ }
++
+ ISAKMP_SA_established(st->st_connection, st->st_serialno);
+
+ /* ??? If st->st_connectionc->gw_info != NULL,
+@@ -2288,6 +2303,21 @@ main_inR3_tail(struct msg_digest *md
+ */
+ memcpy(st->st_ph1_iv, st->st_new_iv, st->st_new_iv_len);
+ st->st_ph1_iv_len = st->st_new_iv_len;
++
++ /* It seems as per Cisco implementation, XAUTH and MODECFG
++ * are not supposed to be performed again during rekey */
++ if(st->st_connection->newest_isakmp_sa != SOS_NOBODY &&
++ st->st_connection->spd.this.xauth_client) {
++ DBG(DBG_CONTROL, DBG_log("Skipping XAUTH for rekey for Cisco Peer compatibility."));
++ st->hidden_variables.st_xauth_client_done = TRUE;
++ st->st_oakley.xauth = 0;
++
++ if(st->st_connection->spd.this.modecfg_client) {
++ DBG(DBG_CONTROL, DBG_log("Skipping ModeCFG for rekey for Cisco Peer compatibility."));
++ st->hidden_variables.st_modecfg_vars_set = TRUE;
++ st->hidden_variables.st_modecfg_started = TRUE;
++ }
++ }
+
+ ISAKMP_SA_established(st->st_connection, st->st_serialno);
+
More information about the scm-commits
mailing list