[Swan-dev] IKEv2 rekey saga

Matt Rogers mrogers at redhat.com
Wed May 28 23:42:30 EEST 2014


Here's what I have so far. With the event replacement changes in the patch,
ipsecdoi_replace initiates and sends a new Parent SA when the old one expires.
The rekeymargin options also don't seem to work with IKEv2 (since it's not
negotiated?) so I needed a hack to delay the delete event otherwise it goes
right out after the first IKE message on the rekey.

So we get to ikev2parent_outI1 to rekey. I don't understand the policy part of
this in regards to the addition of a pending state, as it seems that we need our
new SA's to pend until they are established and the code later on expects that
it can find a pending state. 

It does:

        if (HAS_IPSEC_POLICY(policy)) {                            
#ifdef HAVE_LABELED_IPSEC                                                                 
                st->sec_ctx = NULL;                                                       
                if ( uctx != NULL)                                                        
                        libreswan_log(                                                    
                                "Labeled ipsec is not supported with ikev2 yet");         
#endif                                                                                    
                add_pending(dup_any(whack_sock), st, c, policy, 1,                        
                            predecessor == NULL ? SOS_NOBODY : predecessor->st_serialno   
#ifdef HAVE_LABELED_IPSEC                                                                 
                            , st->sec_ctx                                                 
#endif                                                                                    
                            );                                                            

Before we rekey the IPSEC part of the policy is removed. So this is confusing
and I work around it in the patch.

Now we rekey:

May 28 15:45:15 west pluto[16030]: | event after this is EVENT_PENDING_DDNS in 3 seconds                         
May 28 15:45:15 west pluto[16030]: | processing connection rekey                                                 
May 28 15:45:15 west pluto[16030]: "rekey" #1: replacing stale ISAKMP SA                                         
May 28 15:45:15 west pluto[16030]: | creating state object #3 at 0x7f64366d6630                                  
May 28 15:45:15 west pluto[16030]: | processing connection rekey                                                 
May 28 15:45:15 west pluto[16030]: | ICOOKIE:  f0 48 39 19  c8 3c 58 e8                                          
May 28 15:45:15 west pluto[16030]: | RCOOKIE:  00 00 00 00  00 00 00 00                                          
May 28 15:45:15 west pluto[16030]: | state hash entry 20                                                         
May 28 15:45:15 west pluto[16030]: | inserting state object #3                                                   
May 28 15:45:15 west pluto[16030]: | inserting event EVENT_SO_DISCARD, timeout in 0 seconds for #3               
May 28 15:45:15 west pluto[16030]: | event added at head of queue                                                
May 28 15:45:15 west pluto[16030]: | processing connection rekey                                                 
May 28 15:45:15 west pluto[16030]: | Queuing pending Quick Mode with 192.168.1.113 "rekey"                       
May 28 15:45:15 west pluto[16030]: "rekey" #3: initiating v2 parent SA to replace #1                             

v2R1 comes back and:

May 28 15:45:16 west pluto[16030]: | PSK auth octets  cf 29 10 e6  1d 7b bc c1  61 8c 38 6b  6d e4 47 0d     
May 28 15:45:16 west pluto[16030]: | emitting 16 raw bytes of PSK auth into IKEv2 Authentication Payload     
May 28 15:45:16 west pluto[16030]: | PSK auth  cf 29 10 e6  1d 7b bc c1  61 8c 38 6b  6d e4 47 0d            
May 28 15:45:16 west pluto[16030]: | emitting length of IKEv2 Authentication Payload: 24                     
May 28 15:45:16 west pluto[16030]: | kernel_alg_db_new() initial trans_cnt=0                                 
May 28 15:45:16 west pluto[16030]: | kernel_alg_db_new() will return p_new->protoid=0, p_new->trans_cnt=0    
May 28 15:45:16 west pluto[16030]: | returning new proposal from esp_info                                    
May 28 15:45:16 west pluto[16030]: | *****emit IKEv2 Security Association Payload:                           
May 28 15:45:16 west pluto[16030]: |    next payload type: ISAKMP_NEXT_v2TSi                                 
May 28 15:45:16 west pluto[16030]: |    critical bit: none                                                   
May 28 15:45:16 west pluto[16030]: | netlink_get_spi: allocated 0xf99f3a87 for esp.0 at 192.168.1.112           
<crash> :(

Program received signal SIGSEGV, Segmentation fault.
ikev2_out_sa (outs=outs at entry=0x7fffb9898920, protoid=protoid at entry=3, sadb=0x7f1e871eb330, st=0x7f1e871f1c50, parentSA=parentSA at entry=0, np=np at entry=44 ',') at /root/libreswan-test/programs/pluto/ikev2_spdb_struct.c:149
(gdb) bt
#0  ikev2_out_sa (outs=outs at entry=0x7fffb9898920, protoid=protoid at entry=3, sadb=0x7f1e871eb330, st=0x7f1e871f1c50, parentSA=parentSA at entry=0, np=np at entry=44 ',') at /root/libreswan-test/programs/pluto/ikev2_spdb_struct.c:149
#1  0x00007f1e86529485 in ikev2_emit_ipsec_sa (md=md at entry=0x7f1e871c6aa0, outpbs=outpbs at entry=0x7fffb9898920, np=np at entry=44, c=c at entry=0x7f1e871c00c0, policy=<optimized out>) at /root/libreswan-test/programs/pluto/ikev2_spdb_struct.c:175
8
#2  0x00007f1e86521cd4 in ikev2_parent_inR1outI2_tail (pcrc=pcrc at entry=0x7f1e871ecad0, r=r at entry=0x7fffb9898b70) at /root/libreswan-test/programs/pluto/ikev2_parent.c:1625
#3  0x00007f1e86522005 in ikev2_parent_inR1outI2_continue (pcrc=0x7f1e871ecad0, r=0x7fffb9898b70, ugh=<optimized out>) at /root/libreswan-test/programs/pluto/ikev2_parent.c:1168

This happens at:

144|         for (pc_cnt = 0; pc_cnt < sadb->prop_disj_cnt; pc_cnt++) {
145|                 struct db_v2_prop *vp = &sadb->prop_disj[pc_cnt];
146|                 unsigned int pr_cnt;
147|
148|                 /* now send out all the transforms */
149+>                for (pr_cnt = 0; pr_cnt < vp->prop_cnt; pr_cnt++) {
150|                         unsigned int ts_cnt;
151|                         struct db_v2_prop_conj *vpc = &vp->props[pr_cnt];

(gdb) p vp
$1 = (struct db_v2_prop *) 0x0

(gdb) p *sadb
$4 = {
  dynamic = 1,
  parentSA = 0,
  prop_conjs = 0x7f1e871f56c0,
  prop_conj_cnt = 1,
  prop_disj = 0x0,
  prop_disj_cnt = 1
}

I can't tell why the prop_disj data is missing here. Any ideas?

While IKEv2 rekeying without a CREATE_CHILD_SA seems hacky enough so I don't 
want to butcher this too much :)

Matt
-------------- next part --------------
diff --git a/include/pluto_constants.h b/include/pluto_constants.h
index 88fa7ab..b0e174b 100644
--- a/include/pluto_constants.h
+++ b/include/pluto_constants.h
@@ -437,6 +437,10 @@ enum phase1_role {
 
 #define IS_PARENT_SA(st) (!IS_CHILD_SA(st))
 
+#define V1_V2_IKESA(st)  (IS_PHASE1(st->st_state) || \
+			  IS_PHASE15(st->st_state) || \
+			  IS_PARENT_SA(st))
+
 /* kind of struct connection
  * Ordered (mostly) by concreteness.  Order is exploited.
  */
diff --git a/programs/pluto/ikev2_parent.c b/programs/pluto/ikev2_parent.c
index 324610c..ed5868f 100644
--- a/programs/pluto/ikev2_parent.c
+++ b/programs/pluto/ikev2_parent.c
@@ -124,7 +124,7 @@ stf_status ikev2parent_outI1(int whack_sock,
 	st->st_msgid_nextuse = 0;
 	st->st_try   = try;
 
-	if (HAS_IPSEC_POLICY(policy)) {
+	if (HAS_IPSEC_POLICY(policy) || predecessor != NULL) {
 #ifdef HAVE_LABELED_IPSEC
 		st->sec_ctx = NULL;
 		if ( uctx != NULL)
diff --git a/programs/pluto/timer.c b/programs/pluto/timer.c
index 1e919b0..7d94944 100644
--- a/programs/pluto/timer.c
+++ b/programs/pluto/timer.c
@@ -627,11 +627,11 @@ void handle_next_timer_event(void)
 	{
 		struct connection *c;
 		so_serial_t newest;
+		time_t margin;
 
 		passert(st != NULL);
 		c = st->st_connection;
-		newest = (IS_PHASE1(st->st_state) ||
-			IS_PHASE15(st->st_state )) ?
+		newest = V1_V2_IKESA(st) ?
 			c->newest_isakmp_sa : c->newest_ipsec_sa;
 
 		if (newest > st->st_serialno &&
@@ -640,9 +640,8 @@ void handle_next_timer_event(void)
 			DBG(DBG_LIFECYCLE,
 				libreswan_log(
 					"not replacing stale %s SA: #%lu will do",
-					(IS_PHASE1(st->st_state) ||
-						IS_PHASE15(st->st_state )) ?
-					"ISAKMP" : "IPsec", newest));
+					 V1_V2_IKESA(st) ?
+					 "ISAKMP" : "IPsec", newest));
 		} else if (type == EVENT_SA_REPLACE_IF_USED   &&
 			st->st_outbound_time <= tm - c->sa_rekey_margin) {
 			/*
@@ -666,22 +665,26 @@ void handle_next_timer_event(void)
 			DBG(DBG_LIFECYCLE,
 				libreswan_log(
 					"not replacing stale %s SA: inactive for %lus",
-					(IS_PHASE1(st->st_state) ||
-						IS_PHASE15(st->st_state )) ?
-						"ISAKMP" : "IPsec",
+					 V1_V2_IKESA(st) ? "ISAKMP" : "IPsec",
 					(unsigned long)(tm -
 						st->st_outbound_time)));
 		} else {
 			DBG(DBG_LIFECYCLE,
 				libreswan_log("replacing stale %s SA",
-					(IS_PHASE1(st->st_state) ||
-						IS_PHASE15(st->st_state)) ?
-					"ISAKMP" : "IPsec"));
+					      V1_V2_IKESA(st) ?
+					      "ISAKMP" : "IPsec"));
 			ipsecdoi_replace(st, LEMPTY, LEMPTY, 1);
 		}
 		delete_liveness_event(st);
 		delete_dpd_event(st);
-		event_schedule(EVENT_SA_EXPIRE, st->st_margin, st);
+
+		/* XXX hack - get around st->st_margin being 0 here on ikev2 rekey for the moment */
+		if (st->st_ikev2 && st->st_margin < 1)
+			margin = 10;
+		else
+			margin = st->st_margin;
+
+		event_schedule(EVENT_SA_EXPIRE, margin, st);
 	}
 	break;
 
@@ -694,7 +697,7 @@ void handle_next_timer_event(void)
 		passert(st != NULL);
 		c = st->st_connection;
 
-		if (IS_PHASE1(st->st_state) || IS_PHASE15(st->st_state)) {
+		if (V1_V2_IKESA(st)) {
 			satype = "ISAKMP";
 			latest = c->newest_isakmp_sa;
 		} else {


More information about the Swan-dev mailing list