diff options
author | 2017-03-27 10:21:19 +0000 | |
---|---|---|
committer | 2017-03-27 10:21:19 +0000 | |
commit | d4bcf9ebd95c6933434ac4d074533cecf28392c1 (patch) | |
tree | a414f125144382662e8dc7359835293bc65aa3cd | |
parent | Add support for RFC4754 (ECDSA) and RFC7427 authentication. (diff) | |
download | wireguard-openbsd-d4bcf9ebd95c6933434ac4d074533cecf28392c1.tar.xz wireguard-openbsd-d4bcf9ebd95c6933434ac4d074533cecf28392c1.zip |
Add support to reflect the responder IKEv2 COOKIE.
This fixes connecting to Azure VPN and other implementations that
implement the IKEv2 COOKIE mechanism on the responder side. Azure
decides to send you a responder COOKIE after too many connection
attempts - we have to keep it and reflect it to establish a
connection. This implementation is only for the initiator (client)
side, we do not support sending COOKIEs on the responder (server) side
yet.
OK patrick@ mikeb@
-rw-r--r-- | sbin/iked/iked.h | 3 | ||||
-rw-r--r-- | sbin/iked/ikev2.c | 59 | ||||
-rw-r--r-- | sbin/iked/ikev2_msg.c | 5 | ||||
-rw-r--r-- | sbin/iked/ikev2_pld.c | 23 | ||||
-rw-r--r-- | sbin/iked/types.h | 5 |
5 files changed, 82 insertions, 13 deletions
diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h index b2bda61d145..997ec1a56e4 100644 --- a/sbin/iked/iked.h +++ b/sbin/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.110 2017/03/27 10:06:41 reyk Exp $ */ +/* $OpenBSD: iked.h,v 1.111 2017/03/27 10:21:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -502,6 +502,7 @@ struct iked_message { struct iked_id msg_auth; /* AUTH payload */ struct iked_id msg_id; struct iked_id msg_cert; + struct ibuf *msg_cookie; /* Parse stack */ struct iked_proposal *msg_prop; diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c index 6f01901925d..0f11d9ea293 100644 --- a/sbin/iked/ikev2.c +++ b/sbin/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.144 2017/03/27 10:06:41 reyk Exp $ */ +/* $OpenBSD: ikev2.c,v 1.145 2017/03/27 10:21:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -63,7 +63,7 @@ void ikev2_init_recv(struct iked *, struct iked_message *, struct ike_header *); void ikev2_init_ike_sa_timeout(struct iked *, void *); int ikev2_init_ike_sa_peer(struct iked *, struct iked_policy *, - struct iked_addr *); + struct iked_addr *, struct iked_message *); int ikev2_init_ike_auth(struct iked *, struct iked_sa *); int ikev2_init_auth(struct iked *, struct iked_message *); int ikev2_init_done(struct iked *, struct iked_sa *); @@ -734,6 +734,7 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, struct iked_sa *sa; in_port_t port; struct iked_socket *sock; + struct iked_policy *pol; if (ikev2_msg_valid_ike_sa(env, hdr, msg) == -1) { log_debug("%s: unknown SA", __func__); @@ -799,6 +800,14 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, switch (hdr->ike_exchange) { case IKEV2_EXCHANGE_IKE_SA_INIT: + if (ibuf_length(msg->msg_cookie)) { + pol = sa->sa_policy; + if (ikev2_init_ike_sa_peer(env, pol, + &pol->pol_peer, msg) != 0) + log_warnx("%s: failed to initiate a " + "IKE_SA_INIT exchange", __func__); + break; + } (void)ikev2_init_auth(env, msg); break; case IKEV2_EXCHANGE_IKE_AUTH: @@ -833,7 +842,7 @@ ikev2_init_ike_sa(struct iked *env, void *arg) log_debug("%s: initiating \"%s\"", __func__, pol->pol_name); - if (ikev2_init_ike_sa_peer(env, pol, &pol->pol_peer)) + if (ikev2_init_ike_sa_peer(env, pol, &pol->pol_peer, NULL)) log_debug("%s: failed to initiate with peer %s", __func__, print_host((struct sockaddr *)&pol->pol_peer.addr, @@ -858,15 +867,16 @@ ikev2_init_ike_sa_timeout(struct iked *env, void *arg) int ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, - struct iked_addr *peer) + struct iked_addr *peer, struct iked_message *retry) { struct sockaddr_storage ss; struct iked_message req; struct ike_header *hdr; struct ikev2_payload *pld; struct ikev2_keyexchange *ke; - struct iked_sa *sa; - struct ibuf *buf; + struct ikev2_notify *n; + struct iked_sa *sa = NULL; + struct ibuf *buf, *cookie = NULL; struct group *group; ssize_t len; int ret = -1; @@ -876,13 +886,21 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, if ((sock = ikev2_msg_getsocket(env, peer->addr_af, 0)) == NULL) return (-1); + if (retry != NULL) { + sa = retry->msg_sa; + cookie = retry->msg_cookie; + sa_state(env, sa, IKEV2_STATE_INIT); + } + /* Create a new initiator SA */ - if ((sa = sa_new(env, 0, 0, 1, pol)) == NULL) + if (sa == NULL && + (sa = sa_new(env, 0, 0, 1, pol)) == NULL) return (-1); /* Pick peer's DH group if asked */ /* XXX free old sa_dhgroup ? */ sa->sa_dhgroup = pol->pol_peerdh; + sa->sa_reqid = 0; if (ikev2_sa_initiator(env, sa, NULL, NULL) == -1) goto done; @@ -909,9 +927,31 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol, /* IKE header */ if ((hdr = ikev2_add_header(buf, sa, req.msg_msgid, - IKEV2_PAYLOAD_SA, IKEV2_EXCHANGE_IKE_SA_INIT, 0)) == NULL) + cookie == NULL ? IKEV2_PAYLOAD_SA : IKEV2_PAYLOAD_NOTIFY, + IKEV2_EXCHANGE_IKE_SA_INIT, 0)) == NULL) goto done; + /* Reflect COOKIE */ + if (cookie) { + if ((pld = ikev2_add_payload(buf)) == NULL) + goto done; + if ((n = ibuf_advance(buf, sizeof(*n))) == NULL) + goto done; + n->n_protoid = IKEV2_SAPROTO_NONE; + n->n_spisize = 0; + n->n_type = htobe16(IKEV2_N_COOKIE); + if (ikev2_add_buf(buf, cookie) == -1) + goto done; + len = sizeof(*n) + ibuf_size(cookie); + + log_debug("%s: added cookie, len %zu", __func__, + ibuf_size(cookie)); + print_hex(ibuf_data(cookie), 0, ibuf_size(cookie)); + + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) + goto done; + } + /* SA payload */ if ((pld = ikev2_add_payload(buf)) == NULL) goto done; @@ -5176,7 +5216,8 @@ ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire) log_debug("%s: found matching policy '%s'", __func__, p->pol_name); - if (ikev2_init_ike_sa_peer(env, p, acquire->flow_peer) != 0) + if (ikev2_init_ike_sa_peer(env, p, + acquire->flow_peer, NULL) != 0) log_warnx("%s: failed to initiate a " "IKE_SA_INIT exchange", __func__); } else { diff --git a/sbin/iked/ikev2_msg.c b/sbin/iked/ikev2_msg.c index 37bb8995425..6658414e57b 100644 --- a/sbin/iked/ikev2_msg.c +++ b/sbin/iked/ikev2_msg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_msg.c,v 1.50 2017/03/27 10:06:41 reyk Exp $ */ +/* $OpenBSD: ikev2_msg.c,v 1.51 2017/03/27 10:21:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -183,12 +183,15 @@ ikev2_msg_cleanup(struct iked *env, struct iked_message *msg) ibuf_release(msg->msg_auth.id_buf); ibuf_release(msg->msg_id.id_buf); ibuf_release(msg->msg_cert.id_buf); + ibuf_release(msg->msg_cookie); msg->msg_nonce = NULL; msg->msg_ke = NULL; msg->msg_auth.id_buf = NULL; msg->msg_id.id_buf = NULL; msg->msg_cert.id_buf = NULL; + msg->msg_cookie = NULL; + config_free_proposals(&msg->msg_proposals, 0); } diff --git a/sbin/iked/ikev2_pld.c b/sbin/iked/ikev2_pld.c index 51a95b488fc..9aeb61eb987 100644 --- a/sbin/iked/ikev2_pld.c +++ b/sbin/iked/ikev2_pld.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_pld.c,v 1.59 2017/03/13 18:48:16 mikeb Exp $ */ +/* $OpenBSD: ikev2_pld.c,v 1.60 2017/03/27 10:21:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -1289,6 +1289,27 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, msg->msg_sa->sa_cpi_out = betoh16(cpi); } break; + case IKEV2_N_COOKIE: + if (msg->msg_e) { + log_debug("%s: N_COOKIE encrypted", + __func__); + return (-1); + } + if (len < IKED_COOKIE_MIN || len > IKED_COOKIE_MAX) { + log_debug("%s: ignoring malformed cookie" + " notification: %zu", __func__, len); + return (0); + } + log_debug("%s: received cookie, len %zu", __func__, len); + print_hex(buf, 0, len); + + ibuf_release(msg->msg_cookie); + if ((msg->msg_cookie = ibuf_new(buf, len)) == NULL) { + log_debug("%s: failed to get peer cookie", __func__); + return (-1); + } + msg->msg_parent->msg_cookie = msg->msg_cookie; + break; case IKEV2_N_SIGNATURE_HASH_ALGORITHMS: if (msg->msg_e) { log_debug("%s: SIGNATURE_HASH_ALGORITHMS: encrypted", diff --git a/sbin/iked/types.h b/sbin/iked/types.h index 0e878887ea7..8e29d39f0ee 100644 --- a/sbin/iked/types.h +++ b/sbin/iked/types.h @@ -1,4 +1,4 @@ -/* $OpenBSD: types.h,v 1.26 2017/01/03 17:51:38 reyk Exp $ */ +/* $OpenBSD: types.h,v 1.27 2017/03/27 10:21:19 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -56,6 +56,9 @@ #define IKED_NONCE_MIN 16 /* XXX 128 bits */ #define IKED_NONCE_SIZE 32 /* XXX 256 bits */ +#define IKED_COOKIE_MIN 1 /* min 1 bytes */ +#define IKED_COOKIE_MAX 64 /* max 64 bytes */ + #define IKED_ID_SIZE 1024 /* XXX should be dynamic */ #define IKED_PSK_SIZE 1024 /* XXX should be dynamic */ #define IKED_MSGBUF_MAX 8192 |