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));