Update: Having the use_transport_mode flag attached to the SA is
not the best idea, so now it is given down to the child SA as soon as
possible and then only looked up from there (and cleared in the parent).
A simple setup looks as follows:

For A (/etc/iked.conf):
ikev2 "test" active transport esp from A to B \
        peer B

For B (/etc/iked.conf):
ikev2 "test" active transport esp from B to A \
        peer A

If successful ipsecctl -ssa (on both hosts) shows:

esp transport from A to B spi 0xedf7b2e6 auth hmac-sha2-256 enc aes-256
esp transport from B to A spi 0xedf7b2e6 auth hmac-sha2-256 enc aes-256

ok?

Here's the diff:

Index: iked.conf.5
===================================================================
RCS file: /mount/openbsd/cvs/src/sbin/iked/iked.conf.5,v
retrieving revision 1.55
diff -u -p -u -r1.55 iked.conf.5
--- iked.conf.5 11 May 2019 16:30:23 -0000      1.55
+++ iked.conf.5 13 Aug 2019 12:23:48 -0000
@@ -268,6 +268,15 @@ specifies that
 .Xr ipcomp 4 ,
 the IP Payload Compression protocol, is negotiated in addition to 
encapsulation.
 The optional compression is applied before packets are encapsulated.
+.It Op Ar tmode
+.Ar tmode
+describes the encapsulation mode to be used.
+Possible modes are
+.Ar tunnel
+and
+.Ar transport ;
+the default is
+.Ar tunnel .
 .It Op Ar encap
 .Ar encap
 specifies the encapsulation protocol to be used.
@@ -277,15 +286,6 @@ and
 .Ar ah ;
 the default is
 .Ar esp .
-.\" .It Op Ar tmode
-.\" .Ar tmode
-.\" describes the encapsulation mode to be used.
-.\" Possible modes are
-.\" .Ar tunnel
-.\" and
-.\" .Ar transport ;
-.\" the default is
-.\" .Ar tunnel .
 .It Op Ar af
 This policy only applies to endpoints of the specified address family
 which can be either
Index: iked.h
===================================================================
RCS file: /mount/openbsd/cvs/src/sbin/iked/iked.h,v
retrieving revision 1.122
diff -u -p -u -r1.122 iked.h
--- iked.h      12 Aug 2019 07:40:45 -0000      1.122
+++ iked.h      13 Aug 2019 12:23:48 -0000
@@ -251,6 +251,7 @@ struct iked_policy {
 #define IKED_POLICY_QUICK               0x08
 #define IKED_POLICY_SKIP                0x10
 #define IKED_POLICY_IPCOMP              0x20
+#define IKED_POLICY_TRANSPORT           0x40
 
        int                              pol_refcnt;
 
@@ -465,6 +466,7 @@ struct iked_sa {
 
        int                              sa_mobike;     /* MOBIKE */
        int                              sa_frag;       /* fragmentation */
+       int                              sa_use_transport_mode; /* should be 
reset */
 
        struct iked_timer                sa_timer;      /* SA timeouts */
 #define IKED_IKE_SA_EXCHANGE_TIMEOUT    300            /* 5 minutes */
Index: ikev2.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sbin/iked/ikev2.c,v
retrieving revision 1.172
diff -u -p -u -r1.172 ikev2.c
--- ikev2.c     12 Aug 2019 07:40:45 -0000      1.172
+++ ikev2.c     13 Aug 2019 12:47:49 -0000
@@ -148,8 +148,12 @@ ssize_t ikev2_add_nat_detection(struct i
 ssize_t ikev2_add_fragmentation(struct iked *, struct ibuf *,
            struct ikev2_payload **, struct iked_message *, ssize_t);
 
+ssize_t         ikev2_add_notify(struct iked *, struct ibuf *,
+           struct ikev2_payload **, ssize_t, struct iked_sa *, uint16_t);
 ssize_t         ikev2_add_mobike(struct iked *, struct ibuf *,
            struct ikev2_payload **, ssize_t, struct iked_sa *);
+ssize_t         ikev2_add_transport_mode(struct iked *, struct ibuf *,
+           struct ikev2_payload **, ssize_t, struct iked_sa *);
 int     ikev2_update_sa_addresses(struct iked *, struct iked_sa *);
 int     ikev2_resp_informational(struct iked *, struct iked_sa *,
            struct iked_message *);
@@ -1238,10 +1242,13 @@ ikev2_init_ike_auth(struct iked *env, st
                        goto done;
        }
 
-       /* compression */
+       /* compression, transport mode */
        if ((pol->pol_flags & IKED_POLICY_IPCOMP) &&
            (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1)
                goto done;
+       if ((pol->pol_flags & IKED_POLICY_TRANSPORT) &&
+           (len = ikev2_add_transport_mode(env, e, &pld, len, sa)) == -1)
+               goto done;
 
        if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1)
                goto done;
@@ -1685,8 +1692,9 @@ ikev2_add_ipcompnotify(struct iked *env,
 }
 
 ssize_t
-ikev2_add_mobike(struct iked *env, struct ibuf *e,
-    struct ikev2_payload **pld, ssize_t len, struct iked_sa *sa)
+ikev2_add_notify(struct iked *env, struct ibuf *e,
+    struct ikev2_payload **pld, ssize_t len, struct iked_sa *sa,
+    uint16_t notify)
 {
        struct ikev2_notify             *n;
        uint8_t                         *ptr;
@@ -1702,13 +1710,27 @@ ikev2_add_mobike(struct iked *env, struc
        n = (struct ikev2_notify *)ptr;
        n->n_protoid = 0;
        n->n_spisize = 0;
-       n->n_type = htobe16(IKEV2_N_MOBIKE_SUPPORTED);
+       n->n_type = htobe16(notify);
        log_debug("%s: done", __func__);
 
        return (len);
 }
 
 ssize_t
+ikev2_add_mobike(struct iked *env, struct ibuf *e,
+    struct ikev2_payload **pld, ssize_t len, struct iked_sa *sa)
+{
+       return  ikev2_add_notify(env, e, pld, len, sa, 
IKEV2_N_MOBIKE_SUPPORTED);
+}
+
+ssize_t
+ikev2_add_transport_mode(struct iked *env, struct ibuf *e,
+    struct ikev2_payload **pld, ssize_t len, struct iked_sa *sa)
+{
+       return  ikev2_add_notify(env, e, pld, len, sa, 
IKEV2_N_USE_TRANSPORT_MODE);
+}
+
+ssize_t
 ikev2_add_fragmentation(struct iked *env, struct ibuf *buf,
     struct ikev2_payload **pld, struct iked_message *msg, ssize_t len)
 {
@@ -2735,6 +2757,7 @@ ikev2_resp_ike_auth(struct iked *env, st
        struct ikev2_auth               *auth;
        struct iked_id                  *id, *certid;
        struct ibuf                     *e = NULL;
+       struct iked_childsa             *csa = NULL;
        uint8_t                          firstpayload;
        int                              ret = -1;
        ssize_t                          len;
@@ -2825,10 +2848,14 @@ ikev2_resp_ike_auth(struct iked *env, st
                        goto done;
        }
 
-       /* compression */
+       /* compression, transport mode */
        if (sa->sa_ipcomp &&
            (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1)
                goto done;
+       if ((csa = TAILQ_FIRST(&sa->sa_childsas)) != NULL &&
+           csa->csa_transport &&
+           (len = ikev2_add_transport_mode(env, e, &pld, len, sa)) == -1)
+               goto done;
 
        /* MOBIKE */
        if (sa->sa_mobike &&
@@ -3068,10 +3095,13 @@ ikev2_send_create_child_sa(struct iked *
        if ((e = ibuf_static()) == NULL)
                goto done;
 
-       /* compression */
+       /* compression, transport mode */
        if ((pol->pol_flags & IKED_POLICY_IPCOMP) &&
            (len = ikev2_add_ipcompnotify(env, e, &pld, 0, sa)) == -1)
                goto done;
+       if ((pol->pol_flags & IKED_POLICY_TRANSPORT) &&
+           (len = ikev2_add_transport_mode(env, e, &pld, 0, sa)) == -1)
+               goto done;
 
        if (pld) {
                firstpayload = IKEV2_PAYLOAD_NOTIFY;
@@ -3684,7 +3714,7 @@ ikev2_ikesa_recv_delete(struct iked *env
 int
 ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg)
 {
-       struct iked_childsa             *csa = NULL;
+       struct iked_childsa             *csa = NULL, *newcsa = NULL;
        struct iked_proposal            *prop;
        struct iked_proposals            proposals;
        struct iked_kex                 *kex, *kextmp = NULL;
@@ -3852,10 +3882,14 @@ ikev2_resp_create_child_sa(struct iked *
        if ((e = ibuf_static()) == NULL)
                goto done;
 
-       /* compression (unless IKE rekeying) */
+       /* compression, transport mode (unless IKE rekeying) */
        if (!nsa && sa->sa_ipcomp &&
            (len = ikev2_add_ipcompnotify(env, e, &pld, 0, sa)) == -1)
                goto done;
+       if (!nsa && (newcsa = TAILQ_FIRST(&sa->sa_childsas)) != NULL &&
+           newcsa->csa_transport &&
+           (len = ikev2_add_transport_mode(env, e, &pld, 0, sa)) == -1)
+               goto done;
 
        if (pld) {
                firstpayload = IKEV2_PAYLOAD_NOTIFY;
@@ -5224,6 +5258,7 @@ ikev2_childsa_negotiate(struct iked *env
                csa->csa_spi.spi_protoid = prop->prop_protoid;
                csa->csa_esn = esn;
                csa->csa_acquired = acquired;
+               csa->csa_transport = sa->sa_use_transport_mode;
 
                /* Set up responder's SPIs */
                if (initiator) {
@@ -5310,6 +5345,7 @@ ikev2_childsa_negotiate(struct iked *env
 
        ret = 0;
  done:
+       sa->sa_use_transport_mode = 0;          /* reset state after use */
        ibuf_release(dhsecret);
        ibuf_release(keymat);
        ibuf_release(seed);
Index: ikev2_pld.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sbin/iked/ikev2_pld.c,v
retrieving revision 1.72
diff -u -p -u -r1.72 ikev2_pld.c
--- ikev2_pld.c 12 Aug 2019 07:40:45 -0000      1.72
+++ ikev2_pld.c 13 Aug 2019 12:30:01 -0000
@@ -1198,6 +1198,20 @@ ikev2_pld_notify(struct iked *env, struc
                /* enforce natt */
                msg->msg_sa->sa_natt = 1;
                break;
+       case IKEV2_N_USE_TRANSPORT_MODE:
+               if (!msg->msg_e) {
+                       log_debug("%s: N_USE_TRANSPORT_MODE not encrypted",
+                           __func__);
+                       return (-1);
+               }
+               if (len != 0) {
+                       log_debug("%s: ignoring malformed transport mode"
+                           " notification: %zu", __func__, len);
+                       return (0);
+               }
+               if (msg->msg_policy->pol_flags & IKED_POLICY_TRANSPORT)
+                       msg->msg_parent->msg_sa->sa_use_transport_mode = 1;
+               break;
        case IKEV2_N_UPDATE_SA_ADDRESSES:
                if (!msg->msg_e) {
                        log_debug("%s: N_UPDATE_SA_ADDRESSES not encrypted",
Index: parse.y
===================================================================
RCS file: /mount/openbsd/cvs/src/sbin/iked/parse.y,v
retrieving revision 1.81
diff -u -p -u -r1.81 parse.y
--- parse.y     28 Jun 2019 13:32:44 -0000      1.81
+++ parse.y     13 Aug 2019 12:23:48 -0000
@@ -414,7 +414,7 @@ typedef struct {
 %type  <v.id>                  id
 %type  <v.transforms>          transforms
 %type  <v.filters>             filters
-%type  <v.ikemode>             ikeflags ikematch ikemode ipcomp
+%type  <v.ikemode>             ikeflags ikematch ikemode ipcomp tmode
 %type  <v.ikeauth>             ikeauth
 %type  <v.ikekey>              keyspec
 %type  <v.mode>                ike_sas child_sas
@@ -851,7 +851,7 @@ child_sa    : CHILDSA       {
                }
                ;
 
-ikeflags       : ikematch ikemode ipcomp       { $$ = $1 | $2 | $3; }
+ikeflags       : ikematch ikemode ipcomp tmode { $$ = $1 | $2 | $3 | $4; }
                ;
 
 ikematch       : /* empty */                   { $$ = 0; }
@@ -867,6 +867,11 @@ ikemode            : /* empty */                   { $$ = 
IKED_POL
 
 ipcomp         : /* empty */                   { $$ = 0; }
                | IPCOMP                        { $$ = IKED_POLICY_IPCOMP; }
+               ;
+
+tmode          : /* empty */                   { $$ = 0; }
+               | TUNNEL                        { $$ = 0; }
+               | TRANSPORT                     { $$ = IKED_POLICY_TRANSPORT; }
                ;
 
 ikeauth                : /* empty */                   {

Reply via email to