Hi,

the following diffs allows to use iked/OpenIKED with iOS9 IKEv2
clients.  You will be able to connect your super-large iPad Pro or
premium iPhone 6s+ via OpenBSD :) I don't have El Capitan yet, but it
might fix it for your super-light MacBook as well.

Problem: iOS doesn't send a CERTREQ but just a CERT and expects us to
respond with a CERT as well.  Without the diff, iked does not send
back a CERT without a CERTREQ payload in the request (list of CA SHA1
hashes).  RFC 7296 (yep, they updated the IKEv2 RFC again) says in
section 3.7 that the CERTREQ payload is optional and only a
suggestion.  The implementation is allowed to select its certificate
based on other policies.  Apple's implementation (btw., what is it
based on?) seems to interpret it as "select and send a CERT even if
the CERTREQ is missing".

The attached diff always responds with a CERT or public key.  If the
peer didn't send a CERTREQ, iked now picks a cert based on its own
trusted CAs (which usually includes the CA that signed your local
cert).

In the iOS VPN configuration, I successfully tested it with User
Authentication "Username" (EAP-MSCHAPv2), "None" + "Use Certificate",
and "None" + "Secret" (psk).  Take care to configure the "Remote ID"
and "Local ID" correctly (it should be (U)FQDN or IPv4/6, not
ASN1_DN).  I also had to import .pfx cert+key and a .crt CA via Safari
on the device.  User Authentication "Certificate" is not supported, as
it is EAP-TLS.  The matching "Username" iked.conf follows:

user "user1" "password123"
ikev2 "ios9" passive esp \
        from 0.0.0.0/0 to 0.0.0.0/0 \
        local any peer any \
        eap "mschap-v2" \
        config address 10.2.0.1/24 \
        config name-server 10.2.0.2 \
        tag "$name-$id"

The iOS9 client currently only advertises enc aes-128 auth hmac-sha1
group modp1024, which is fairly vintage crypto, but there was a hint
that we could potentially get it to send better proposals by
responding with "no proposal chosen" at some point.  Will try it later.


OK?

Reyk

Index: sbin/iked/ca.c
===================================================================
RCS file: /cvs/src/sbin/iked/ca.c,v
retrieving revision 1.36
diff -u -p -u -p -r1.36 ca.c
--- sbin/iked/ca.c      21 Aug 2015 11:59:27 -0000      1.36
+++ sbin/iked/ca.c      30 Sep 2015 14:37:28 -0000
@@ -248,7 +248,7 @@ ca_setcert(struct iked *env, struct iked
 }
 
 int
-ca_setreq(struct iked *env, struct iked_sahdr *sh,
+ca_setreq(struct iked *env, struct iked_sa *sa,
     struct iked_static_id *localid, uint8_t type, uint8_t *data,
     size_t len, enum privsep_procid procid)
 {
@@ -273,8 +273,8 @@ ca_setreq(struct iked *env, struct iked_
        iov[iovcnt].iov_len = sizeof(idb);
        iovcnt++;
 
-       iov[iovcnt].iov_base = sh;
-       iov[iovcnt].iov_len = sizeof(*sh);
+       iov[iovcnt].iov_base = &sa->sa_hdr;
+       iov[iovcnt].iov_len = sizeof(sa->sa_hdr);
        iovcnt++;
        iov[iovcnt].iov_base = &type;
        iov[iovcnt].iov_len = sizeof(type);
@@ -286,6 +286,8 @@ ca_setreq(struct iked *env, struct iked_
        if (proc_composev_imsg(&env->sc_ps, procid, -1,
            IMSG_CERTREQ, -1, iov, iovcnt) == -1)
                goto done;
+
+       sa_stateflags(sa, IKED_REQ_CERTREQ);
 
        ret = 0;
  done:
Index: sbin/iked/iked.h
===================================================================
RCS file: /cvs/src/sbin/iked/iked.h,v
retrieving revision 1.88
diff -u -p -u -p -r1.88 iked.h
--- sbin/iked/iked.h    21 Aug 2015 11:59:27 -0000      1.88
+++ sbin/iked/iked.h    30 Sep 2015 14:37:29 -0000
@@ -322,17 +322,19 @@ struct iked_id {
        struct ibuf     *id_buf;
 };
 
-#define IKED_REQ_CERT          0x01    /* get local certificate (if required) 
*/
-#define IKED_REQ_CERTVALID     0x02    /* validated the peer cert */
-#define IKED_REQ_AUTH          0x04    /* AUTH payload */
-#define IKED_REQ_AUTHVALID     0x08    /* AUTH payload has been verified */
-#define IKED_REQ_SA            0x10    /* SA available */
-#define IKED_REQ_EAPVALID      0x20    /* EAP payload has been verified */
-#define IKED_REQ_CHILDSA       0x40    /* Child SA initiated */
-#define IKED_REQ_INF           0x80    /* Informational exchange initiated */
+#define IKED_REQ_CERT          0x0001  /* get local certificate (if required) 
*/
+#define IKED_REQ_CERTVALID     0x0002  /* validated the peer cert */
+#define IKED_REQ_CERTREQ       0x0004  /* CERTREQ has been received */
+#define IKED_REQ_AUTH          0x0008  /* AUTH payload */
+#define IKED_REQ_AUTHVALID     0x0010  /* AUTH payload has been verified */
+#define IKED_REQ_SA            0x0020  /* SA available */
+#define IKED_REQ_EAPVALID      0x0040  /* EAP payload has been verified */
+#define IKED_REQ_CHILDSA       0x0080  /* Child SA initiated */
+#define IKED_REQ_INF           0x0100  /* Informational exchange initiated */
 
 #define IKED_REQ_BITS  \
-    "\20\01CERT\02CERTVALID\03AUTH\04AUTHVALID\05SA\06EAP"
+    "\20\01CERT\02CERTVALID\03CERTREQ\04AUTH\05AUTHVALID\06SA\07EAPVALID" \
+    "\10CHILDSA\11INF"
 
 TAILQ_HEAD(iked_msgqueue, iked_message);
 
@@ -838,7 +840,7 @@ void         pfkey_init(struct iked *, int fd);
 
 /* ca.c */
 pid_t   caproc(struct privsep *, struct privsep_proc *);
-int     ca_setreq(struct iked *, struct iked_sahdr *, struct iked_static_id *,
+int     ca_setreq(struct iked *, struct iked_sa *, struct iked_static_id *,
            uint8_t, uint8_t *, size_t, enum privsep_procid);
 int     ca_setcert(struct iked *, struct iked_sahdr *, struct iked_id *,
            uint8_t, uint8_t *, size_t, enum privsep_procid);
Index: sbin/iked/ikev2.c
===================================================================
RCS file: /cvs/src/sbin/iked/ikev2.c,v
retrieving revision 1.123
diff -u -p -u -p -r1.123 ikev2.c
--- sbin/iked/ikev2.c   21 Aug 2015 11:59:27 -0000      1.123
+++ sbin/iked/ikev2.c   30 Sep 2015 14:37:32 -0000
@@ -652,6 +652,8 @@ ikev2_ike_auth_recv(struct iked *env, st
 int
 ikev2_ike_auth(struct iked *env, struct iked_sa *sa)
 {
+       struct iked_policy      *pol = sa->sa_policy;
+
        /* Attempt state transition */
        if (sa->sa_state == IKEV2_STATE_EAP_SUCCESS)
                sa_state(env, sa, IKEV2_STATE_EAP_VALID);
@@ -664,6 +666,24 @@ ikev2_ike_auth(struct iked *env, struct 
                else
                        return (ikev2_init_ike_auth(env, sa));
        }
+
+       /*
+        * If we have to send a local certificate but did not receive an
+        * optional CERTREQ, use our own certreq to find a local certificate.
+        * We could alternatively extract the CA from the peer certificate
+        * to find a matching local one.
+        */
+       if (sa->sa_statevalid & IKED_REQ_CERT) {
+               if ((sa->sa_stateflags & IKED_REQ_CERTREQ) == 0) {
+                       log_debug("%s: no CERTREQ, using default", __func__);
+                       return (ca_setreq(env, sa,
+                           &pol->pol_localid, pol->pol_certreqtype,
+                           ibuf_data(env->sc_certreq),
+                           ibuf_size(env->sc_certreq), PROC_CERT));
+               } else if ((sa->sa_stateflags & IKED_REQ_CERT) == 0)
+                       return (0);     /* ignored, wait for cert */
+       }
+
        return (ikev2_resp_ike_auth(env, sa));
 }
 
Index: sbin/iked/ikev2_pld.c
===================================================================
RCS file: /cvs/src/sbin/iked/ikev2_pld.c,v
retrieving revision 1.52
diff -u -p -u -p -r1.52 ikev2_pld.c
--- sbin/iked/ikev2_pld.c       21 Aug 2015 11:59:27 -0000      1.52
+++ sbin/iked/ikev2_pld.c       30 Sep 2015 14:37:34 -0000
@@ -931,7 +931,7 @@ ikev2_pld_certreq(struct iked *env, stru
        else
                sa->sa_statevalid |= IKED_REQ_CERT;
 
-       ca_setreq(env, &sa->sa_hdr, &sa->sa_policy->pol_localid,
+       ca_setreq(env, sa, &sa->sa_policy->pol_localid,
            cert.cert_type, buf, len, PROC_CERT);
 
        return (0);
Index: sbin/iked/policy.c
===================================================================
RCS file: /cvs/src/sbin/iked/policy.c,v
retrieving revision 1.39
diff -u -p -u -p -r1.39 policy.c
--- sbin/iked/policy.c  21 Aug 2015 11:59:28 -0000      1.39
+++ sbin/iked/policy.c  30 Sep 2015 14:37:34 -0000
@@ -272,7 +272,7 @@ sa_stateflags(struct iked_sa *sa, unsign
        else
                require = sa->sa_stateinit;
 
-       log_debug("%s: 0x%02x -> 0x%02x %s (required 0x%02x %s)", __func__,
+       log_debug("%s: 0x%04x -> 0x%04x %s (required 0x%04x %s)", __func__,
            sa->sa_stateflags, sa->sa_stateflags | flags,
            print_bits(sa->sa_stateflags | flags, IKED_REQ_BITS), require,
            print_bits(require, IKED_REQ_BITS));
@@ -296,7 +296,7 @@ sa_stateok(struct iked_sa *sa, int state
        if (state == IKEV2_STATE_SA_INIT ||
            state == IKEV2_STATE_VALID ||
            state == IKEV2_STATE_EAP_VALID) {
-               log_debug("%s: %s flags 0x%02x, require 0x%02x %s", __func__,
+               log_debug("%s: %s flags 0x%04x, require 0x%04x %s", __func__,
                    print_map(state, ikev2_state_map),
                    (sa->sa_stateflags & require), require,
                    print_bits(require, IKED_REQ_BITS));

Reply via email to