diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2014-02-14 09:00:04 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2014-02-14 09:00:04 +0000 |
commit | f4e9a9ffa848780f796a2edef5fa8e2d43dcecff (patch) | |
tree | 712e5771110f6982e21a8f8bc7369a74c3ddec28 | |
parent | bc74558dd64e1cf7d15e7047cddaf618301aa4ea (diff) |
initial support for IPComp
still experimental and rekeying needs some work; ok mikeb@
-rw-r--r-- | sbin/iked/iked.h | 8 | ||||
-rw-r--r-- | sbin/iked/ikev2.c | 173 | ||||
-rw-r--r-- | sbin/iked/ikev2.h | 3 | ||||
-rw-r--r-- | sbin/iked/ikev2_pld.c | 21 | ||||
-rw-r--r-- | sbin/iked/parse.y | 14 | ||||
-rw-r--r-- | sbin/iked/pfkey.c | 17 | ||||
-rw-r--r-- | sbin/iked/util.c | 5 |
7 files changed, 227 insertions, 14 deletions
diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h index 2cb80473c91..75334b87ae8 100644 --- a/sbin/iked/iked.h +++ b/sbin/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.65 2014/01/24 07:31:25 markus Exp $ */ +/* $OpenBSD: iked.h,v 1.66 2014/02/14 09:00:03 markus Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -165,6 +165,7 @@ struct iked_childsa { u_int8_t csa_allocated; /* from the kernel */ u_int8_t csa_persistent;/* do not rekey */ u_int8_t csa_esn; /* use ESN */ + u_int8_t csa_transport; /* transport mode */ struct iked_spi csa_spi; @@ -238,6 +239,7 @@ struct iked_policy { #define IKED_POLICY_REFCNT 0x04 #define IKED_POLICY_QUICK 0x08 #define IKED_POLICY_SKIP 0x10 +#define IKED_POLICY_IPCOMP 0x20 int pol_refcnt; @@ -404,6 +406,10 @@ struct iked_sa { struct iked_childsas sa_childsas; /* IPSec Child SAs */ struct iked_saflows sa_flows; /* IPSec flows */ + u_int8_t sa_ipcomp; /* IPcomp transform */ + u_int16_t sa_cpi_out; /* IPcomp outgoing */ + u_int16_t sa_cpi_in; /* IPcomp incoming*/ + struct iked_timer sa_timer; /* SA timeouts */ #define IKED_IKE_SA_REKEY_TIMEOUT 300 /* 5 minutes */ #define IKED_IKE_SA_ALIVE_TIMEOUT 60 /* 1 minute */ diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c index 2714013900e..8c61528f8a6 100644 --- a/sbin/iked/ikev2.c +++ b/sbin/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.91 2014/01/24 07:35:55 markus Exp $ */ +/* $OpenBSD: ikev2.c,v 1.92 2014/02/14 09:00:03 markus Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -100,10 +100,14 @@ ssize_t ikev2_add_ts(struct ibuf *, struct ikev2_payload **, ssize_t, struct iked_sa *, int); ssize_t ikev2_add_certreq(struct ibuf *, struct ikev2_payload **, ssize_t, struct ibuf *, u_int8_t); +ssize_t ikev2_add_ipcompnotify(struct iked *, struct ibuf *, + struct ikev2_payload **, ssize_t, struct iked_sa *); ssize_t ikev2_add_ts_payload(struct ibuf *, u_int, struct iked_sa *); int ikev2_add_data(struct ibuf *, void *, size_t); int ikev2_add_buf(struct ibuf *buf, struct ibuf *); +int ikev2_ipcomp_enable(struct iked_sa *); + static struct privsep_proc procs[] = { { "parent", PROC_PARENT, ikev2_dispatch_parent }, { "ikev1", PROC_IKEV1, ikev2_dispatch_ikev1 }, @@ -1010,6 +1014,11 @@ ikev2_init_ike_auth(struct iked *env, struct iked_sa *sa) goto done; } + /* compression */ + if ((pol->pol_flags & IKED_POLICY_IPCOMP) && + (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1) + goto done; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) goto done; @@ -1347,6 +1356,57 @@ ikev2_add_certreq(struct ibuf *e, struct ikev2_payload **pld, ssize_t len, return (len); } +ssize_t +ikev2_add_ipcompnotify(struct iked *env, struct ibuf *e, + struct ikev2_payload **pld, ssize_t len, struct iked_sa *sa) +{ + struct iked_childsa csa; + struct ikev2_notify *n; + u_int8_t *ptr; + u_int16_t cpi; + u_int32_t spi; + u_int8_t transform; + + /* we only support deflate */ + transform = IKEV2_IPCOMP_DEFLATE; + + bzero(&csa, sizeof(csa)); + csa.csa_saproto = IKEV2_SAPROTO_IPCOMP; + csa.csa_ikesa = sa; + csa.csa_local = &sa->sa_peer; + csa.csa_peer = &sa->sa_local; + + if (pfkey_sa_init(env->sc_pfkey, &csa, &spi) == -1) + return (-1); + /* + * We get spi == 0 if the kernel does not support IPcomp, + * so just return the length of the current payload. + */ + if (spi == 0) + return (len); + cpi = htobe16((u_int16_t)spi); + if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_NOTIFY) == -1) + return (-1); + if ((*pld = ikev2_add_payload(e)) == NULL) + return (-1); + len = sizeof(*n) + sizeof(cpi) + sizeof(transform); + if ((ptr = ibuf_advance(e, len)) == NULL) + return (-1); + n = (struct ikev2_notify *)ptr; + n->n_protoid = 0; + n->n_spisize = 0; + n->n_type = htobe16(IKEV2_N_IPCOMP_SUPPORTED); + ptr += sizeof(*n); + memcpy(ptr, &cpi, sizeof(cpi)); + ptr += sizeof(cpi); + memcpy(ptr, &transform, sizeof(transform)); + + sa->sa_cpi_in = spi; /* already on host byte order */ + log_debug("%s: sa_cpi_in 0x%04x", __func__, sa->sa_cpi_in); + + return (len); +} + int ikev2_next_payload(struct ikev2_payload *pld, size_t length, u_int8_t nextpayload) @@ -2075,6 +2135,11 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) goto done; } + /* compression */ + if (sa->sa_ipcomp && + (len = ikev2_add_ipcompnotify(env, e, &pld, len, sa)) == -1) + goto done; + if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_SA) == -1) goto done; @@ -2692,6 +2757,9 @@ ikev2_ike_sa_alive(struct iked *env, void *arg) /* check for incoming traffic on any child SA */ TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) { + if (!csa->csa_loaded || + csa->csa_saproto == IKEV2_SAPROTO_IPCOMP) + continue; if (pfkey_sa_last_used(env->sc_pfkey, csa, &last_used) != 0) continue; gettimeofday(&tv, NULL); @@ -3832,11 +3900,114 @@ ikev2_childsa_negotiate(struct iked *env, struct iked_sa *sa, int initiator) } int +ikev2_ipcomp_enable(struct iked_sa *sa) +{ + struct iked_childsa *other, *csa = NULL, *csb = NULL; + struct iked_flow *flow, *flowa = NULL, *flowb = NULL; + + if ((csa = calloc(1, sizeof(*csa))) == NULL || + (csb = calloc(1, sizeof(*csb))) == NULL || + (flowa = calloc(1, sizeof(*flowa))) == NULL || + (flowb = calloc(1, sizeof(*flowb))) == NULL) { + free(csa); + free(csb); + free(flowa); + free(flowb); + return (-1); + } + + /* switch ESP SAs to transport mode */ + TAILQ_FOREACH(other, &sa->sa_childsas, csa_entry) + if (!other->csa_rekey && !other->csa_loaded && + other->csa_saproto == IKEV2_SAPROTO_ESP) + other->csa_transport = 1; + + /* install IPCOMP SAs */ + csa->csa_ikesa = sa; + csa->csa_saproto = IKEV2_SAPROTO_IPCOMP; + if (sa->sa_hdr.sh_initiator) { + csa->csa_dstid = &sa->sa_rid; + csa->csa_srcid = &sa->sa_iid; + } else { + csa->csa_dstid = &sa->sa_iid; + csa->csa_srcid = &sa->sa_rid; + } + csa->csa_spi.spi_size = 2; + csa->csa_spi.spi = sa->sa_cpi_out; + csa->csa_peerspi = sa->sa_cpi_in; + csa->csa_dir = IPSP_DIRECTION_OUT; + csa->csa_local = &sa->sa_local; + csa->csa_peer = &sa->sa_peer; + csb->csa_allocated = 0; + + memcpy(csb, csa, sizeof(*csb)); + csb->csa_spi.spi = csa->csa_peerspi; + csb->csa_peerspi = csa->csa_spi.spi; + csb->csa_dir = IPSP_DIRECTION_IN; + csb->csa_local = csa->csa_peer; + csb->csa_peer = csa->csa_local; + csb->csa_allocated = 1; + + TAILQ_INSERT_TAIL(&sa->sa_childsas, csa, csa_entry); + TAILQ_INSERT_TAIL(&sa->sa_childsas, csb, csa_entry); + + csa->csa_peersa = csb; + csb->csa_peersa = csa; + + /* redirect flows to IPCOMP */ + TAILQ_FOREACH(flow, &sa->sa_flows, flow_entry) { + if (flow->flow_loaded || + flow->flow_saproto != IKEV2_SAPROTO_ESP) + continue; + log_debug("%s: flow %p saproto %d -> %d", __func__, + flow, flow->flow_saproto, IKEV2_SAPROTO_IPCOMP); + flow->flow_saproto = IKEV2_SAPROTO_IPCOMP; + } + + /* setup ESP flows for gateways */ + flowa->flow_dir = IPSP_DIRECTION_OUT; + flowa->flow_saproto = IKEV2_SAPROTO_ESP; + if (sa->sa_hdr.sh_initiator) { + flowa->flow_dstid = &sa->sa_rid; + flowa->flow_srcid = &sa->sa_iid; + } else { + flowa->flow_dstid = &sa->sa_iid; + flowa->flow_srcid = &sa->sa_rid; + } + flowa->flow_local = &sa->sa_local; + flowa->flow_peer = &sa->sa_peer; + memcpy(&flowa->flow_src, &sa->sa_local, sizeof(sa->sa_local)); + memcpy(&flowa->flow_dst, &sa->sa_peer, sizeof(sa->sa_peer)); + flowa->flow_src.addr_mask = flowa->flow_dst.addr_mask = + (sa->sa_local.addr_af == AF_INET) ? 32 : 128; + flowa->flow_src.addr_port = flowa->flow_dst.addr_port = 0; + flowa->flow_ikesa = sa; + + memcpy(flowb, flowa, sizeof(*flowb)); + flowb->flow_dir = IPSP_DIRECTION_IN; + memcpy(&flowb->flow_dst, &flowa->flow_src, sizeof(flowa->flow_src)); + memcpy(&flowb->flow_src, &flowa->flow_dst, sizeof(flowa->flow_dst)); + + TAILQ_INSERT_TAIL(&sa->sa_flows, flowa, flow_entry); + TAILQ_INSERT_TAIL(&sa->sa_flows, flowb, flow_entry); + + /* make sure IPCOMP CPIs are not reused */ + sa->sa_ipcomp = 0; + sa->sa_cpi_in = sa->sa_cpi_out = 0; + + return (0); +} + +int ikev2_childsa_enable(struct iked *env, struct iked_sa *sa) { struct iked_childsa *csa; struct iked_flow *flow, *oflow; + if (sa->sa_ipcomp && sa->sa_cpi_in && sa->sa_cpi_out && + ikev2_ipcomp_enable(sa) == -1) + return (-1); + TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) { if (csa->csa_rekey || csa->csa_loaded) continue; diff --git a/sbin/iked/ikev2.h b/sbin/iked/ikev2.h index 439e8ab38b6..e8dbf7b5d76 100644 --- a/sbin/iked/ikev2.h +++ b/sbin/iked/ikev2.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.h,v 1.12 2013/03/30 16:31:37 reyk Exp $ */ +/* $OpenBSD: ikev2.h,v 1.13 2014/02/14 09:00:03 markus Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -125,6 +125,7 @@ struct ikev2_sa_proposal { #define IKEV2_SAPROTO_ESP 3 /* ESP */ #define IKEV2_SAPROTO_FC_ESP_HEADER 4 /* RFC4595 */ #define IKEV2_SAPROTO_FC_CT_AUTH 5 /* RFC4595 */ +#define IKEV2_SAPROTO_IPCOMP 204 /* private, should be 4 */ extern struct iked_constmap ikev2_saproto_map[]; diff --git a/sbin/iked/ikev2_pld.c b/sbin/iked/ikev2_pld.c index 9dc7b45e78f..df5ca6a5fc2 100644 --- a/sbin/iked/ikev2_pld.c +++ b/sbin/iked/ikev2_pld.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_pld.c,v 1.36 2014/02/12 12:59:44 markus Exp $ */ +/* $OpenBSD: ikev2_pld.c,v 1.37 2014/02/14 09:00:03 markus Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -650,6 +650,8 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, struct iked_spi *rekey; u_int16_t type; u_int16_t group; + u_int16_t cpi; + u_int8_t transform; if ((n = ibuf_seek(msg->msg_data, offset, sizeof(*n))) == NULL) return (-1); @@ -753,6 +755,23 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld, print_map(n->n_protoid, ikev2_saproto_map), print_spi(rekey->spi, n->n_spisize)); break; + case IKEV2_N_IPCOMP_SUPPORTED: + if (len < sizeof(cpi) + sizeof(transform)) { + log_debug("%s: malformed ipcomp notification", + __func__); + return (0); + } + memcpy(&cpi, buf, sizeof(cpi)); + memcpy(&transform, buf + sizeof(cpi), sizeof(transform)); + log_debug("%s: cpi 0x%x, transform %s, len %d", __func__, + betoh16(cpi), print_map(transform, ikev2_ipcomp_map), len); + /* we only support deflate */ + if ((msg->msg_policy->pol_flags & IKED_POLICY_IPCOMP) && + (transform == IKEV2_IPCOMP_DEFLATE)) { + msg->msg_sa->sa_ipcomp = transform; + msg->msg_sa->sa_cpi_out = betoh16(cpi); + } + break; } return (0); diff --git a/sbin/iked/parse.y b/sbin/iked/parse.y index b8864672e10..e9e14f5a4c3 100644 --- a/sbin/iked/parse.y +++ b/sbin/iked/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.35 2014/01/22 00:21:16 henning Exp $ */ +/* $OpenBSD: parse.y,v 1.36 2014/02/14 09:00:03 markus Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -369,6 +369,7 @@ typedef struct { %token PASSIVE ACTIVE ANY TAG TAP PROTO LOCAL GROUP NAME CONFIG EAP USER %token IKEV1 FLOW SA TCPMD5 TUNNEL TRANSPORT COUPLE DECOUPLE SET %token INCLUDE LIFETIME BYTES INET INET6 QUICK SKIP DEFAULT +%token IPCOMP %token <v.string> STRING %token <v.number> NUMBER %type <v.string> string @@ -385,7 +386,7 @@ typedef struct { %type <v.id> id %type <v.transforms> transforms %type <v.filters> filters -%type <v.ikemode> ikeflags ikematch ikemode +%type <v.ikemode> ikeflags ikematch ikemode ipcomp %type <v.ikeauth> ikeauth %type <v.ikekey> keyspec %type <v.mode> ike_sa child_sa @@ -752,7 +753,7 @@ ike_sa : /* empty */ { encxfs = ikeencxfs; } transforms { if (($$ = calloc(1, sizeof(*$$))) == NULL) - err(1, "child_sa: calloc"); + err(1, "ike_sa: calloc"); $$->xfs = $3; } ; @@ -769,7 +770,7 @@ child_sa : /* empty */ { } ; -ikeflags : ikematch ikemode { $$ = $1 | $2; } +ikeflags : ikematch ikemode ipcomp { $$ = $1 | $2 | $3; } ; ikematch : /* empty */ { $$ = 0; } @@ -783,6 +784,10 @@ ikemode : /* empty */ { $$ = IKED_POLICY_PASSIVE; } | ACTIVE { $$ = IKED_POLICY_ACTIVE; } ; +ipcomp : /* empty */ { $$ = 0; } + | IPCOMP { $$ = IKED_POLICY_IPCOMP; } + ; + ikeauth : /* empty */ { $$.auth_method = IKEV2_AUTH_RSA_SIG; $$.auth_length = 0; @@ -1077,6 +1082,7 @@ lookup(char *s) { "include", INCLUDE }, { "inet", INET }, { "inet6", INET6 }, + { "ipcomp", IPCOMP }, { "lifetime", LIFETIME }, { "local", LOCAL }, { "name", NAME }, diff --git a/sbin/iked/pfkey.c b/sbin/iked/pfkey.c index 18510859c57..1c97009d60d 100644 --- a/sbin/iked/pfkey.c +++ b/sbin/iked/pfkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfkey.c,v 1.27 2014/01/22 09:25:41 markus Exp $ */ +/* $OpenBSD: pfkey.c,v 1.28 2014/02/14 09:00:03 markus Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -99,6 +99,7 @@ static const struct pfkey_constmap pfkey_integr[] = { static const struct pfkey_constmap pfkey_satype[] = { { SADB_SATYPE_AH, IKEV2_SAPROTO_AH }, { SADB_SATYPE_ESP, IKEV2_SAPROTO_ESP }, + { SADB_X_SATYPE_IPCOMP, IKEV2_SAPROTO_IPCOMP }, { 0 } }; @@ -478,8 +479,8 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) sadb.sadb_sa_state = SADB_SASTATE_MATURE; sadb.sadb_sa_replay = 64; - /* XXX we don't support transport mode, yet */ - sadb.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; + if (!sa->csa_transport) + sadb.sadb_sa_flags |= SADB_X_SAFLAGS_TUNNEL; if (sa->csa_esn) sadb.sadb_sa_flags |= SADB_X_SAFLAGS_ESN; @@ -526,7 +527,8 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) return (-1); } - if (sa->csa_ikesa->sa_udpencap && sa->csa_ikesa->sa_natt) { + if (satype == SADB_SATYPE_ESP && + sa->csa_ikesa->sa_udpencap && sa->csa_ikesa->sa_natt) { sadb.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP; udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP; udpencap.sadb_x_udpencap_len = sizeof(udpencap) / 8; @@ -571,6 +573,10 @@ pfkey_sa(int sd, u_int8_t satype, u_int8_t action, struct iked_childsa *sa) 8 * ibuf_size(sa->csa_encrkey); } + /* we only support deflate */ + if (satype == SADB_X_SATYPE_IPCOMP) + sadb.sadb_sa_encrypt = SADB_X_CALG_DEFLATE; + /* local id */ sa_srcid = pfkey_id2ident(sa->csa_srcid, SADB_EXT_IDENTITY_SRC); @@ -861,7 +867,8 @@ pfkey_sa_getspi(int sd, u_int8_t satype, struct iked_childsa *sa, sa_spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; sa_spirange.sadb_spirange_len = sizeof(sa_spirange) / 8; sa_spirange.sadb_spirange_min = 0x100; - sa_spirange.sadb_spirange_max = 0xffffffff; + sa_spirange.sadb_spirange_max = (satype == SADB_X_SATYPE_IPCOMP) ? + (CPI_PRIVATE_MIN - 1) : 0xffffffff; sa_spirange.sadb_spirange_reserved = 0; bzero(&sa_src, sizeof(sa_src)); diff --git a/sbin/iked/util.c b/sbin/iked/util.c index 77de1c406c3..dcdedf3a815 100644 --- a/sbin/iked/util.c +++ b/sbin/iked/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.23 2013/12/03 13:55:40 markus Exp $ */ +/* $OpenBSD: util.c,v 1.24 2014/02/14 09:00:03 markus Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -361,6 +361,9 @@ print_spi(u_int64_t spi, int size) ptr = buf[i]; switch (size) { + case 2: + snprintf(ptr, 32, "0x%04x", (u_int16_t)spi); + break; case 4: snprintf(ptr, 32, "0x%08x", (u_int32_t)spi); break; |