diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2010-06-14 23:14:10 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2010-06-14 23:14:10 +0000 |
commit | 4352486464fdc177d68bb32455b40349f6e081e7 (patch) | |
tree | 3ee5dc23be40d9547778967d57df2f2e3d635560 /sbin | |
parent | ec8268c259a5afa181428b71aa9f1588cdb63186 (diff) |
Initiator mode with certificates; needs more work but works.
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/iked/iked.h | 5 | ||||
-rw-r--r-- | sbin/iked/ikev2.c | 108 | ||||
-rw-r--r-- | sbin/iked/ikev2_pld.c | 15 | ||||
-rw-r--r-- | sbin/iked/policy.c | 56 |
4 files changed, 123 insertions, 61 deletions
diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h index d6e39200e77..3b9cf2c85f0 100644 --- a/sbin/iked/iked.h +++ b/sbin/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.10 2010/06/14 21:12:56 reyk Exp $ */ +/* $OpenBSD: iked.h,v 1.11 2010/06/14 23:14:09 reyk Exp $ */ /* $vantronix: iked.h,v 1.61 2010/06/03 07:57:33 reyk Exp $ */ /* @@ -306,7 +306,8 @@ struct iked_sa { int sa_state; u_int sa_stateflags; - u_int sa_staterequire; + u_int sa_stateinit; /* SA_INIT */ + u_int sa_statevalid; /* IKE_AUTH */ int sa_cp; /* XXX */ diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c index 2db3bd36d2f..c0e4a8e9af7 100644 --- a/sbin/iked/ikev2.c +++ b/sbin/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.13 2010/06/14 21:12:56 reyk Exp $ */ +/* $OpenBSD: ikev2.c,v 1.14 2010/06/14 23:14:09 reyk Exp $ */ /* $vantronix: ikev2.c,v 1.101 2010/06/03 07:57:33 reyk Exp $ */ /* @@ -56,12 +56,15 @@ struct iked_sa * u_int8_t *, u_int8_t **, size_t *); void ikev2_recv(struct iked *, struct iked_message *); +int ikev2_ike_auth(struct iked *, struct iked_sa *); void ikev2_init_recv(struct iked *, struct iked_message *, struct ike_header *); int ikev2_init_ike_sa(struct iked *, struct iked_policy *); -int ikev2_init_ike_auth(struct iked *, struct iked_message *); -int ikev2_init_done(struct iked *, 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 *, + struct iked_message *); void ikev2_resp_recv(struct iked *, struct iked_message *, struct ike_header *); @@ -213,14 +216,14 @@ ikev2_dispatch_cert(int fd, struct iked_proc *p, struct imsg *imsg) if (imsg->hdr.type == IMSG_CERTVALID) { log_debug("%s: peer certificate is valid", __func__); + sa_stateflags(sa, IKED_REQ_VALID); sa_state(env, sa, IKEV2_STATE_VALID); - } else + } else { log_debug("%s: peer certificate is invalid", __func__); + } - sa_stateflags(sa, IKED_REQ_VALID); - - if (ikev2_resp_ike_auth(env, sa) != 0) - log_debug("%s: failed to send auth response", __func__); + if (ikev2_ike_auth(env, sa) != 0) + log_debug("%s: failed to send ike auth", __func__); break; case IMSG_CERT: if ((sa = ikev2_getimsgdata(env, imsg, @@ -252,8 +255,8 @@ ikev2_dispatch_cert(int fd, struct iked_proc *p, struct imsg *imsg) sa_stateflags(sa, IKED_REQ_CERT); - if (ikev2_resp_ike_auth(env, sa) != 0) - log_debug("%s: failed to send auth response", __func__); + if (ikev2_ike_auth(env, sa) != 0) + log_debug("%s: failed to send ike auth", __func__); break; case IMSG_AUTH: if ((sa = ikev2_getimsgdata(env, imsg, @@ -279,8 +282,8 @@ ikev2_dispatch_cert(int fd, struct iked_proc *p, struct imsg *imsg) sa_stateflags(sa, IKED_REQ_AUTH); - if (ikev2_resp_ike_auth(env, sa) != 0) - log_debug("%s: failed to send auth response", __func__); + if (ikev2_ike_auth(env, sa) != 0) + log_debug("%s: failed to send ike auth", __func__); break; default: return (-1); @@ -383,6 +386,18 @@ ikev2_recv(struct iked *env, struct iked_message *msg) sa_free(env, sa); } +int +ikev2_ike_auth(struct iked *env, struct iked_sa *sa) +{ + if (sa->sa_hdr.sh_initiator) { + if (sa_stateok(sa, IKEV2_STATE_AUTH_SUCCESS)) + return (ikev2_init_done(env, sa, NULL)); + else + return (ikev2_init_ike_auth(env, sa)); + } + return (ikev2_resp_ike_auth(env, sa)); +} + void ikev2_init_recv(struct iked *env, struct iked_message *msg, struct ike_header *hdr) @@ -425,10 +440,10 @@ ikev2_init_recv(struct iked *env, struct iked_message *msg, switch (hdr->ike_exchange) { case IKEV2_EXCHANGE_IKE_SA_INIT: - (void)ikev2_init_ike_auth(env, msg); + (void)ikev2_init_auth(env, msg); break; case IKEV2_EXCHANGE_IKE_AUTH: - (void)ikev2_init_done(env, msg); + (void)ikev2_init_done(env, sa, msg); break; case IKEV2_EXCHANGE_CREATE_CHILD_SA: default: @@ -580,18 +595,9 @@ ikev2_init_ike_sa(struct iked *env, struct iked_policy *pol) } int -ikev2_init_ike_auth(struct iked *env, struct iked_message *msg) +ikev2_init_auth(struct iked *env, struct iked_message *msg) { struct iked_sa *sa = msg->msg_sa; - struct iked_policy *pol = sa->sa_policy; - struct ikev2_payload *pld; - struct ikev2_cert *cert; - struct ikev2_auth *auth; - struct iked_id *id, *certid; - struct ibuf *e = NULL; - u_int8_t firstpayload; - int ret = -1; - ssize_t len; struct ibuf *authmsg; if (sa == NULL) @@ -608,11 +614,29 @@ ikev2_init_ike_auth(struct iked *env, struct iked_message *msg) return (-1); } - /* XXX this doesn't work with certificates */ - ca_setauth(env, sa, authmsg, PROC_CERT); + if (ca_setauth(env, sa, authmsg, PROC_CERT) == -1) { + log_debug("%s: failed to get cert", __func__); + return (-1); + } + + return (ikev2_init_ike_auth(env, sa)); +} + +int +ikev2_init_ike_auth(struct iked *env, struct iked_sa *sa) +{ + struct iked_policy *pol = sa->sa_policy; + struct ikev2_payload *pld; + struct ikev2_cert *cert; + struct ikev2_auth *auth; + struct iked_id *id, *certid; + struct ibuf *e = NULL; + u_int8_t firstpayload; + int ret = -1; + ssize_t len; if (!sa_stateok(sa, IKEV2_STATE_SA_INIT)) - return (0); /* ignore */ + return (0); if (!sa->sa_localauth.id_type) { log_debug("%s: no local auth", __func__); @@ -635,7 +659,7 @@ ikev2_init_ike_auth(struct iked *env, struct iked_message *msg) len = ibuf_size(id->id_buf); /* CERT payload */ - if ((sa->sa_staterequire & IKED_REQ_CERT) && + if ((sa->sa_stateinit & IKED_REQ_CERT) && (certid->id_type != IKEV2_CERT_NONE)) { if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_CERT) == -1) @@ -648,6 +672,22 @@ ikev2_init_ike_auth(struct iked *env, struct iked_message *msg) if (ibuf_cat(e, certid->id_buf) != 0) goto done; len = ibuf_size(certid->id_buf) + sizeof(*cert); + + if (env->sc_certreqtype) { + if (ikev2_next_payload(pld, len, + IKEV2_PAYLOAD_CERTREQ) == -1) + goto done; + + /* CERTREQ payload */ + if ((pld = ikev2_add_payload(e)) == NULL) + goto done; + if ((cert = ibuf_advance(e, sizeof(*cert))) == NULL) + goto done; + cert->cert_type = env->sc_certreqtype; + if (ikev2_add_buf(e, env->sc_certreq) == -1) + goto done; + len = ibuf_size(env->sc_certreq) + sizeof(*cert); + } } if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_AUTH) == -1) @@ -715,12 +755,12 @@ ikev2_init_ike_auth(struct iked *env, struct iked_message *msg) } int -ikev2_init_done(struct iked *env, struct iked_message *msg) +ikev2_init_done(struct iked *env, struct iked_sa *sa, + struct iked_message *msg) { - struct iked_sa *sa = msg->msg_sa; int ret; - if (!TAILQ_EMPTY(&msg->msg_proposals)) { + if (msg != NULL && !TAILQ_EMPTY(&msg->msg_proposals)) { if (ikev2_sa_negotiate(sa, &sa->sa_policy->pol_proposals, &msg->msg_proposals, IKEV2_SAPROTO_ESP) != 0) { @@ -1518,7 +1558,7 @@ ikev2_resp_ike_sa_init(struct iked *env, struct iked_message *msg) len += sizeof(*n); } - if (env->sc_certreqtype && (sa->sa_staterequire & IKED_REQ_CERT)) { + if (env->sc_certreqtype && (sa->sa_statevalid & IKED_REQ_CERT)) { if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_CERTREQ) == -1) goto done; @@ -1622,7 +1662,7 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa) len = ibuf_size(id->id_buf); /* CERT payload */ - if ((sa->sa_staterequire & IKED_REQ_CERT) && + if ((sa->sa_statevalid & IKED_REQ_CERT) && (certid->id_type != IKEV2_CERT_NONE)) { if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_CERT) == -1) @@ -1743,7 +1783,7 @@ ikev2_resp_ike_eap(struct iked *env, struct iked_sa *sa, struct ibuf *eapmsg) goto done; len = ibuf_size(id->id_buf); - if ((sa->sa_staterequire & IKED_REQ_CERT) && + if ((sa->sa_statevalid & IKED_REQ_CERT) && (certid->id_type != IKEV2_CERT_NONE)) { if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_CERT) == -1) goto done; diff --git a/sbin/iked/ikev2_pld.c b/sbin/iked/ikev2_pld.c index e40597be833..f1bc7c32d48 100644 --- a/sbin/iked/ikev2_pld.c +++ b/sbin/iked/ikev2_pld.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_pld.c,v 1.6 2010/06/14 21:12:56 reyk Exp $ */ +/* $OpenBSD: ikev2_pld.c,v 1.7 2010/06/14 23:14:09 reyk Exp $ */ /* $vantronix: ikev2.c,v 1.101 2010/06/03 07:57:33 reyk Exp $ */ /* @@ -510,10 +510,10 @@ ikev2_pld_cert(struct iked *env, struct ikev2_payload *pld, if (!ikev2_msg_frompeer(msg)) return (0); - if (!sa->sa_hdr.sh_initiator && !msg->msg_response) { + if (!sa->sa_hdr.sh_initiator) { certid = &sa->sa_icert; id = &sa->sa_iid; - } else if (sa->sa_hdr.sh_initiator && msg->msg_response) { + } else if (sa->sa_hdr.sh_initiator) { certid = &sa->sa_rcert; id = &sa->sa_rid; } else @@ -535,6 +535,7 @@ int ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld, struct iked_message *msg, off_t offset) { + struct iked_sa *sa = msg->msg_sa; struct ikev2_cert cert; u_int8_t *buf; size_t len; @@ -562,10 +563,12 @@ ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld, return (-1); /* Optional certreq for PSK */ - msg->msg_sa->sa_staterequire |= IKED_REQ_CERT; + if (sa->sa_hdr.sh_initiator) + sa->sa_stateinit |= IKED_REQ_CERT; + else + sa->sa_statevalid |= IKED_REQ_CERT; - ca_setreq(env, &msg->msg_sa->sa_hdr, cert.cert_type, - buf, len, PROC_CERT); + ca_setreq(env, &sa->sa_hdr, cert.cert_type, buf, len, PROC_CERT); return (0); } diff --git a/sbin/iked/policy.c b/sbin/iked/policy.c index 2833a8616cd..90d09856b91 100644 --- a/sbin/iked/policy.c +++ b/sbin/iked/policy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: policy.c,v 1.7 2010/06/14 21:12:56 reyk Exp $ */ +/* $OpenBSD: policy.c,v 1.8 2010/06/14 23:14:09 reyk Exp $ */ /* $vantronix: policy.c,v 1.29 2010/05/28 15:34:35 reyk Exp $ */ /* @@ -139,10 +139,17 @@ sa_state(struct iked *env, struct iked_sa *sa, int state) void sa_stateflags(struct iked_sa *sa, u_int flags) { + u_int require; + + if (sa->sa_state > IKEV2_STATE_SA_INIT) + require = sa->sa_statevalid; + else + require = sa->sa_stateinit; + log_debug("%s: 0x%02x -> 0x%02x %s (required 0x%02x)", __func__, sa->sa_stateflags, sa->sa_stateflags | flags, print_bits(sa->sa_stateflags | flags, - IKED_REQ_BITS), sa->sa_staterequire); + IKED_REQ_BITS), require); sa->sa_stateflags |= flags; } @@ -150,18 +157,25 @@ sa_stateflags(struct iked_sa *sa, u_int flags) int sa_stateok(struct iked_sa *sa, int state) { + u_int require; + if (sa->sa_state < state) return (0); - if (state == IKEV2_STATE_VALID || + + if (state == IKEV2_STATE_SA_INIT) + require = sa->sa_stateinit; + else + require = sa->sa_statevalid; + + if (state == IKEV2_STATE_SA_INIT || + state == IKEV2_STATE_VALID || state == IKEV2_STATE_EAP) { - log_debug("%s: flags 0x%02x require 0x%02x %s", __func__, - (sa->sa_stateflags & sa->sa_staterequire), - sa->sa_staterequire, - print_bits(sa->sa_staterequire, - IKED_REQ_BITS)); - - if ((sa->sa_stateflags & sa->sa_staterequire) != - sa->sa_staterequire) + log_debug("%s: %s flags 0x%02x, require 0x%02x %s", __func__, + print_map(state, ikev2_state_map), + (sa->sa_stateflags & require), require, + print_bits(require, IKED_REQ_BITS)); + + if ((sa->sa_stateflags & require) != require) return (0); /* not ready, ignore */ } return (1); @@ -173,6 +187,7 @@ sa_new(struct iked *env, u_int64_t ispi, u_int64_t rspi, { struct iked_sa *sa; struct iked_id *localid; + u_int diff; if ((ispi == 0 && rspi == 0) || (sa = sa_lookup(env, ispi, rspi, initiator)) == NULL) { @@ -188,24 +203,27 @@ sa_new(struct iked *env, u_int64_t ispi, u_int64_t rspi, else pol = sa->sa_policy; - sa->sa_staterequire = IKED_REQ_AUTH|IKED_REQ_SA; + sa->sa_statevalid = IKED_REQ_AUTH|IKED_REQ_SA; if (pol != NULL && pol->pol_auth.auth_eap) { - sa->sa_staterequire |= IKED_REQ_CERT; + sa->sa_statevalid |= IKED_REQ_CERT; } else if (pol != NULL && pol->pol_auth.auth_method != IKEV2_AUTH_SHARED_KEY_MIC) { - sa->sa_staterequire |= IKED_REQ_VALID|IKED_REQ_CERT; + sa->sa_statevalid |= IKED_REQ_VALID|IKED_REQ_CERT; } + if (initiator) { + localid = &sa->sa_iid; + diff = IKED_REQ_VALID|IKED_REQ_SA; + sa->sa_stateinit = sa->sa_statevalid & ~diff; + sa->sa_statevalid = sa->sa_statevalid & diff; + } else + localid = &sa->sa_rid; + if (sa->sa_hdr.sh_ispi == 0) sa->sa_hdr.sh_ispi = ispi; if (sa->sa_hdr.sh_rspi == 0) sa->sa_hdr.sh_rspi = rspi; - if (initiator) - localid = &sa->sa_iid; - else - localid = &sa->sa_rid; - if (!ibuf_length(localid->id_buf) && ikev2_policy2id(&pol->pol_localid, localid, 1) != 0) { log_debug("%s: failed to get local id", __func__); |