/* IPsec DOI and Oakley resolution routines * Copyright (C) 1997 Angelos D. Keromytis. * Copyright (C) 1998-2002,2013 D. Hugh Redelmeier * Copyright (C) 2003-2005 Michael Richardson * Copyright (C) 2011 Avesh Agarwal * Copyright (C) 2012 Philippe Vouters * Copyright (C) 2012 Paul Wouters * Copyright (C) 2013 Paul Wouters * Copyright (C) 2013 David McCullough * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See . * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * */ #include #include #include #include #include #include #include #include #include /* for gettimeofday */ #include #include #include "libreswan/pfkeyv2.h" #include "sysdep.h" #include "constants.h" #include "defs.h" #include "state.h" #include "id.h" #include "x509.h" #include "certs.h" #include "connections.h" /* needs id.h */ #include "keys.h" #include "packet.h" #include "demux.h" /* needs packet.h */ #include "adns.h" /* needs */ #include "dnskey.h" /* needs keys.h and adns.h */ #include "kernel.h" /* needs connections.h */ #include "log.h" #include "cookie.h" #include "server.h" #include "spdb.h" #include "timer.h" #include "rnd.h" #include "ipsec_doi.h" /* needs demux.h and state.h */ #include "whack.h" #include "fetch.h" #include "pkcs.h" #include "asn1.h" #include "sha1.h" #include "md5.h" #include "crypto.h" /* requires sha1.h and md5.h */ #include "ike_alg.h" #include "kernel_alg.h" #include "plutoalg.h" #include "pluto_crypt.h" #include "ikev1.h" #include "ikev1_continuations.h" #include "xauth.h" #include "vendor.h" #include "nat_traversal.h" #include "virtual.h" /* needs connections.h */ #include "ikev1_dpd.h" #include "x509more.h" /* STATE_AGGR_R0: HDR, SA, KE, Ni, IDii * --> HDR, SA, KE, Nr, IDir, HASH_R/SIG_R */ static stf_status aggr_inI1_outR1_tail(struct pluto_crypto_req_cont *pcrc, struct pluto_crypto_req *r); static void aggr_inR1_outI2_crypto_continue(struct pluto_crypto_req_cont *pcrc, struct pluto_crypto_req *r, err_t ugh); /* * continuation from second calculation (the DH one) * */ static void aggr_inI1_outR1_continue2(struct pluto_crypto_req_cont *pcrc, struct pluto_crypto_req *r, err_t ugh) { struct dh_continuation *dh = (struct dh_continuation *)pcrc; struct msg_digest *md = dh->dh_md; struct state *const st = md->st; stf_status e; DBG(DBG_CONTROL, DBG_log("aggr_inI1_outR1_continue2 for #%lu: calculated ke+nonce+DH, sending R1", dh->dh_pcrc.pcrc_serialno)); if (st == NULL) { loglog(RC_LOG_SERIOUS, "%s: Request was disconnected from state", __FUNCTION__); passert(dh->dh_pcrc.pcrc_serialno == SOS_NOBODY); /* transitional */ release_any_md(&dh->dh_md); return; } passert(dh->dh_pcrc.pcrc_serialno == st->st_serialno); /* transitional */ /* XXX should check out ugh */ passert(ugh == NULL); passert(cur_state == NULL); passert(st != NULL); passert(st->st_suspended_md == dh->dh_md); unset_suspended(st); /* no longer connected or suspended */ set_cur_state(st); DBG(DBG_CONTROLMORE, DBG_log("#%lu %s:%u st->st_calculating = FALSE;", st->st_serialno, __FUNCTION__, __LINE__)); st->st_calculating = FALSE; e = aggr_inI1_outR1_tail(pcrc, r); if (dh->dh_md != NULL) { complete_v1_state_transition(&dh->dh_md, e); release_any_md(&dh->dh_md); } reset_cur_state(); } /* * for aggressive mode, this is sub-optimal, since we should have * had the crypto helper actually do everything, but we need to do * some additional work to set that all up, so this is fine for now. * */ static void aggr_inI1_outR1_continue1(struct pluto_crypto_req_cont *pcrc, struct pluto_crypto_req *r, err_t ugh) { struct ke_continuation *ke = (struct ke_continuation *)pcrc; struct msg_digest *md = ke->ke_md; struct state *const st = md->st; stf_status e; DBG(DBG_CONTROLMORE, DBG_log("aggr inI1_outR1: calculated ke+nonce, calculating DH")); if (st == NULL) { loglog(RC_LOG_SERIOUS, "%s: Request was disconnected from state", __FUNCTION__); release_any_md(&ke->ke_md); return; } /* XXX should check out ugh */ passert(ugh == NULL); passert(cur_state == NULL); passert(st != NULL); passert(st->st_suspended_md == ke->ke_md); unset_suspended(st); /* no longer connected or suspended */ set_cur_state(st); DBG(DBG_CONTROLMORE, DBG_log("#%lu %s:%u st->st_calculating = FALSE;", st->st_serialno, __FUNCTION__, __LINE__)); st->st_calculating = FALSE; /* unpack first calculation */ unpack_KE(st, r, &st->st_gr); /* unpack nonce too */ unpack_nonce(&st->st_nr, r); /* NOTE: the "r" reply will get freed by our caller */ /* set up second calculation */ { struct dh_continuation *dh = alloc_thing( struct dh_continuation, "aggr outR1 DH"); dh->dh_md = md; set_suspended(st, md); dh->dh_pcrc.pcrc_serialno = st->st_serialno; /* transitional */ pcrc_init(&dh->dh_pcrc, aggr_inI1_outR1_continue2); e = start_dh_secretiv(&dh->dh_pcrc, st, st->st_import, O_RESPONDER, st->st_oakley.group->group); if (e != STF_SUSPEND) { if (dh->dh_md != NULL) { complete_v1_state_transition(&dh->dh_md, e); release_any_md(&dh->dh_md); } } reset_cur_state(); } } static stf_status aggr_inI1_outR1_common(struct msg_digest *md, int authtype) { /* With Aggressive Mode, we get an ID payload in this, the first * message, so we can use it to index the preshared-secrets * when the IP address would not be meaningful (i.e. Road * Warrior). So our first task is to unravel the ID payload. */ struct state *st; struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; struct connection *c = find_host_connection(&md->iface->ip_addr, md->iface->port, &md->sender, md->sender_port, LEMPTY); #if 0 if (c == NULL && md->iface->ike_float) { c = find_host_connection(&md->iface->addr, pluto_nat_port, &md->sender, md->sender_port, LEMPTY); } #endif if (c == NULL) { /* see if a wildcarded connection can be found */ pb_stream pre_sa_pbs = sa_pd->pbs; lset_t policy = preparse_isakmp_sa_body(&pre_sa_pbs) | POLICY_AGGRESSIVE; c = find_host_connection(&md->iface->ip_addr, pluto_port, (ip_address*)NULL, md->sender_port, policy); if (c == NULL || (c->policy & POLICY_AGGRESSIVE) == 0) { ipstr_buf b; loglog(RC_LOG_SERIOUS, "initial Aggressive Mode message from %s" " but no (wildcard) connection has been configured%s%s", ipstr(&md->sender, &b), (policy != LEMPTY) ? " with policy=" : "", (policy != LEMPTY) ? bitnamesof(sa_policy_bit_names, policy) : ""); /* XXX notification is in order! */ return STF_IGNORE; } /* Create a temporary connection that is a copy of this one. * His ID isn't declared yet. */ c = rw_instantiate(c, &md->sender, NULL, NULL); } /* Set up state */ cur_state = md->st = st = new_state(); /* (caller will reset cur_state) */ st->st_connection = c; st->st_remoteaddr = md->sender; st->st_remoteport = md->sender_port; st->st_localaddr = md->iface->ip_addr; st->st_localport = md->iface->port; st->st_interface = md->iface; change_state(st, STATE_AGGR_R1); /* until we have clue who this is, then be conservative about allocating * them any crypto bandwidth */ st->st_import = pcim_stranger_crypto; st->st_policy |= POLICY_AGGRESSIVE; st->st_oakley.auth = authtype; if (!ikev1_decode_peer_id(md, FALSE, TRUE)) { char buf[IDTOA_BUF]; ipstr_buf b; (void) idtoa(&st->st_connection->spd.that.id, buf, sizeof(buf)); loglog(RC_LOG_SERIOUS, "initial Aggressive Mode packet claiming to be from %s" " on %s but no connection has been authorized", buf, ipstr(&md->sender, &b)); /* XXX notification is in order! */ return STF_FAIL + INVALID_ID_INFORMATION; } c = st->st_connection; extra_debugging(c); st->st_try = 0; /* Not our job to try again from start */ st->st_policy = c->policy & ~POLICY_IPSEC_MASK; /* only as accurate as connection */ memcpy(st->st_icookie, md->hdr.isa_icookie, COOKIE_SIZE); get_cookie(FALSE, st->st_rcookie, COOKIE_SIZE, &md->sender); insert_state(st); /* needs cookies, connection, and msgid (0) */ st->st_doi = ISAKMP_DOI_IPSEC; st->st_situation = SIT_IDENTITY_ONLY; /* We only support this */ { ipstr_buf b; libreswan_log("responding to Aggressive Mode, state #%lu, connection \"%s\" from %s", st->st_serialno, st->st_connection->name, ipstr(&c->spd.that.host_addr, &b)); } merge_quirks(st, md); set_nat_traversal(st, md); /* save initiator SA for HASH */ clonereplacechunk(st->st_p1isa, sa_pd->pbs.start, pbs_room(&sa_pd->pbs), "sa in aggr_inI1_outR1()"); /* * parse_isakmp_sa picks the right group, which we need to know * before we do any calculations. We will call it again to have it * emit the winning SA into the output. */ /* SA body in */ { pb_stream sabs = sa_pd->pbs; RETURN_STF_FAILURE(parse_isakmp_sa_body(&sabs, &sa_pd->payload.sa, NULL, FALSE, st)); } /* KE in */ RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, &md->chain[ISAKMP_NEXT_KE]->pbs)); /* Ni in */ RETURN_STF_FAILURE(accept_v1_nonce(md, &st->st_ni, "Ni")); { struct ke_continuation *ke = alloc_thing( struct ke_continuation, "outI2 KE"); ke->ke_md = md; set_suspended(st, md); if (!st->st_sec_in_use) { /* need to calculate KE and Nonce */ pcrc_init(&ke->ke_pcrc, aggr_inI1_outR1_continue1); return build_ke(&ke->ke_pcrc, st, st->st_oakley.group, st->st_import); } else { /* KE and Nonce calculated */ ke->ke_pcrc.pcrc_serialno = st->st_serialno; /* transitional */ return aggr_inI1_outR1_tail(&ke->ke_pcrc, NULL); } } } static void doi_log_cert_thinking(struct msg_digest *md UNUSED, u_int16_t auth, enum ike_cert_type certtype, enum certpolicy policy, bool gotcertrequest, bool send_cert) { DBG(DBG_CONTROL, DBG_log("thinking about whether to send my certificate:")); DBG(DBG_CONTROL, { char esb[ENUM_SHOW_BUF_LEN]; DBG_log(" I have RSA key: %s cert.type: %s ", enum_showb(&oakley_auth_names, auth, esb, sizeof(esb)), enum_show(&ike_cert_type_names, certtype)); }); DBG(DBG_CONTROL, DBG_log(" sendcert: %s and I did%s get a certificate request ", enum_show(&certpolicy_type_names, policy), gotcertrequest ? "" : " not")); DBG(DBG_CONTROL, DBG_log(" so %ssend cert.", send_cert ? "" : "do not ")); if (!send_cert) { if (auth == OAKLEY_PRESHARED_KEY) DBG(DBG_CONTROL, DBG_log("I did not send a certificate because digital signatures are not being used. (PSK)")); else if (certtype == CERT_NONE) DBG(DBG_CONTROL, DBG_log("I did not send a certificate because I do not have one.")); else if (policy == cert_sendifasked) DBG(DBG_CONTROL, DBG_log("I did not send my certificate because I was not asked to.")); } } stf_status aggr_inI1_outR1_psk(struct msg_digest *md) { return aggr_inI1_outR1_common(md, OAKLEY_PRESHARED_KEY); } stf_status aggr_inI1_outR1_rsasig(struct msg_digest *md) { return aggr_inI1_outR1_common(md, OAKLEY_RSA_SIG); } static stf_status aggr_inI1_outR1_tail(struct pluto_crypto_req_cont *pcrc, struct pluto_crypto_req *r) { struct ke_continuation *ke = (struct ke_continuation *)pcrc; struct msg_digest *md = ke->ke_md; struct state *st = md->st; bool send_cert = FALSE; bool send_cr = FALSE; generalName_t *requested_ca = NULL; struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; int auth_payload; cert_t mycert = st->st_connection->spd.this.cert; pb_stream r_sa_pbs; pb_stream r_id_pbs; /* ID Payload; also used for hash calculation */ /* parse_isakmp_sa also spits out a winning SA into our reply, * so we have to build our reply_stream and emit HDR before calling it. */ finish_dh_secretiv(st, r); /* decode certificate requests */ ikev1_decode_cr(md, &requested_ca); if (requested_ca != NULL) st->hidden_variables.st_got_certrequest = TRUE; /* * send certificate if we have one and auth is RSA, and we were * told we can send one if asked, and we were asked, or we were told * to always send one. */ send_cert = st->st_oakley.auth == OAKLEY_RSA_SIG && mycert.ty != CERT_NONE && ((st->st_connection->spd.this.sendcert == cert_sendifasked && st->hidden_variables.st_got_certrequest) || st->st_connection->spd.this.sendcert == cert_alwayssend); doi_log_cert_thinking(md, st->st_oakley.auth, mycert.ty, st->st_connection->spd.this.sendcert, st->hidden_variables.st_got_certrequest, send_cert); /* send certificate request, if we don't have a preloaded RSA public key */ send_cr = send_cert && !has_preloaded_public_key(st); DBG(DBG_CONTROL, DBG_log(" I am %ssending a certificate request", send_cr ? "" : "not ")); /* * free collected certificate requests since as initiator * we don't heed them anyway */ free_generalNames(requested_ca, TRUE); /* done parsing; initialize crypto */ zero(&reply_buffer); init_pbs(&reply_stream, reply_buffer, sizeof(reply_buffer), "reply packet"); /* HDR out */ { struct isakmp_hdr r_hdr = md->hdr; memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); r_hdr.isa_np = ISAKMP_NEXT_SA; if (!out_struct(&r_hdr, &isakmp_hdr_desc, &reply_stream, &md->rbody)) return STF_INTERNAL_ERROR; } /* start of SA out */ { struct isakmp_sa r_sa = sa_pd->payload.sa; notification_t rn; r_sa.isasa_np = ISAKMP_NEXT_KE; if (!out_struct(&r_sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs)) return STF_INTERNAL_ERROR; /* SA body in and out */ rn = parse_isakmp_sa_body(&sa_pd->pbs, &sa_pd->payload.sa, &r_sa_pbs, FALSE, st); if (rn != NOTHING_WRONG) return STF_FAIL + rn; } /* don't know until after SA body has been parsed */ auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG; /************** build rest of output: KE, Nr, IDir, HASH_R/SIG_R ********/ /* KE */ if (!justship_KE(&st->st_gr, &md->rbody, ISAKMP_NEXT_NONCE)) return STF_INTERNAL_ERROR; /* Nr */ if (!justship_nonce(&st->st_nr, &md->rbody, ISAKMP_NEXT_ID, "Nr")) return STF_INTERNAL_ERROR; /* IDir out */ { struct isakmp_ipsec_id id_hd; chunk_t id_b; build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this); id_hd.isaiid_np = (send_cert) ? ISAKMP_NEXT_CERT : auth_payload; if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &r_id_pbs) || !out_chunk(id_b, &r_id_pbs, "my identity")) return STF_INTERNAL_ERROR; close_output_pbs(&r_id_pbs); } /* CERT out */ if (send_cert) { pb_stream cert_pbs; struct isakmp_cert cert_hd; cert_hd.isacert_np = (send_cr) ? ISAKMP_NEXT_CR : ISAKMP_NEXT_SIG; cert_hd.isacert_type = mycert.ty; libreswan_log("I am sending my cert"); if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs)) return STF_INTERNAL_ERROR; if (!out_chunk(get_mycert(mycert), &cert_pbs, "CERT")) return STF_INTERNAL_ERROR; close_output_pbs(&cert_pbs); } /* CR out */ if (send_cr) { libreswan_log("I am sending a certificate request"); if (!ikev1_build_and_ship_CR(mycert.ty, st->st_connection->spd.that.ca, &md->rbody, ISAKMP_NEXT_SIG)) return STF_INTERNAL_ERROR; } update_iv(st); /* HASH_R or SIG_R out */ { u_char hash_val[MAX_DIGEST_LEN]; size_t hash_len = main_mode_hash(st, hash_val, FALSE, &r_id_pbs); if (auth_payload == ISAKMP_NEXT_HASH) { /* HASH_R out */ if (!out_generic_raw(ISAKMP_NEXT_VID, &isakmp_hash_desc, &md->rbody, hash_val, hash_len, "HASH_R")) return STF_INTERNAL_ERROR; } else { /* SIG_R out */ u_char sig_val[RSA_MAX_OCTETS]; size_t sig_len = RSA_sign_hash(st->st_connection, sig_val, hash_val, hash_len); if (sig_len == 0) { loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature"); return STF_FAIL + AUTHENTICATION_FAILED; } if (!out_generic_raw(ISAKMP_NEXT_VID, &isakmp_signature_desc, &md->rbody, sig_val, sig_len, "SIG_R")) return STF_INTERNAL_ERROR; } } /* * NOW SEND VENDOR ID payloads */ if (st->hidden_variables.st_nat_traversal == LEMPTY) { /* Always announce our ability to do RFC 3706 Dead Peer Detection to the peer */ if (!out_vid(ISAKMP_NEXT_NONE, &md->rbody, VID_MISC_DPD)) return STF_INTERNAL_ERROR; } else { /* Always announce our ability to do RFC 3706 Dead Peer Detection to the peer */ if (!out_vid(ISAKMP_NEXT_VID, &md->rbody, VID_MISC_DPD)) return STF_INTERNAL_ERROR; /* and a couple more NAT VIDs */ if (!out_vid(ISAKMP_NEXT_VID, &md->rbody, md->quirks.qnat_traversal_vid)) return STF_INTERNAL_ERROR; if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md)) return STF_INTERNAL_ERROR; } /* finish message */ if (!close_message(&md->rbody, st)) return STF_INTERNAL_ERROR; return STF_OK; } /* STATE_AGGR_I1: HDR, SA, KE, Nr, IDir, HASH_R/SIG_R * --> HDR*, HASH_I/SIG_I */ static stf_status aggr_inR1_outI2_tail(struct msg_digest *md, struct key_continuation *kc); /* forward */ stf_status aggr_inR1_outI2(struct msg_digest *md) { /* With Aggressive Mode, we get an ID payload in this, the second * message, so we can use it to index the preshared-secrets * when the IP address would not be meaningful (i.e. Road * Warrior). So our first task is to unravel the ID payload. */ struct state *st = md->st; st->st_policy |= POLICY_AGGRESSIVE; if (!ikev1_decode_peer_id(md, FALSE, TRUE)) { char buf[IDTOA_BUF]; ipstr_buf b; (void) idtoa(&st->st_connection->spd.that.id, buf, sizeof(buf)); loglog(RC_LOG_SERIOUS, "initial Aggressive Mode packet claiming to be from %s" " on %s but no connection has been authorized", buf, ipstr(&md->sender, &b)); /* XXX notification is in order! */ return STF_FAIL + INVALID_ID_INFORMATION; } /* verify echoed SA */ { struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA]; notification_t r = \ parse_isakmp_sa_body(&sapd->pbs, &sapd->payload.sa, NULL, TRUE, st); if (r != NOTHING_WRONG) return STF_FAIL + r; } merge_quirks(st, md); set_nat_traversal(st, md); /* KE in */ RETURN_STF_FAILURE(accept_KE(&st->st_gr, "Gr", st->st_oakley.group, &md->chain[ISAKMP_NEXT_KE]->pbs)); /* Ni in */ RETURN_STF_FAILURE(accept_v1_nonce(md, &st->st_nr, "Nr")); /* moved the following up as we need Rcookie for hash, skeyids */ /* Reinsert the state, using the responder cookie we just received */ unhash_state(st); memcpy(st->st_rcookie, md->hdr.isa_rcookie, COOKIE_SIZE); insert_state(st); /* needs cookies, connection, and msgid (0) */ ikev1_natd_init(st, md); /* set up second calculation */ { struct dh_continuation *dh = alloc_thing( struct dh_continuation, "aggr outR1 DH"); dh->dh_md = md; set_suspended(st, md); dh->dh_pcrc.pcrc_serialno = st->st_serialno; /* transitional */ pcrc_init(&dh->dh_pcrc, aggr_inR1_outI2_crypto_continue); return start_dh_secretiv(&dh->dh_pcrc, st, st->st_import, O_INITIATOR, st->st_oakley.group->group); } } static void aggr_inR1_outI2_crypto_continue(struct pluto_crypto_req_cont *pcrc, struct pluto_crypto_req *r, err_t ugh) { struct dh_continuation *dh = (struct dh_continuation *)pcrc; struct msg_digest *md = dh->dh_md; struct state *const st = md->st; stf_status e; DBG(DBG_CONTROLMORE, DBG_log("aggr inR1_outI2: calculated DH, sending I2")); if (st == NULL) { loglog(RC_LOG_SERIOUS, "%s: Request was disconnected from state", __FUNCTION__); release_any_md(&dh->dh_md); return; } /* XXX should check out ugh */ passert(ugh == NULL); passert(cur_state == NULL); passert(st != NULL); passert(st->st_suspended_md == dh->dh_md); unset_suspended(st); /* no longer connected or suspended */ set_cur_state(st); DBG(DBG_CONTROLMORE, DBG_log("#%lu %s:%u st->st_calculating = FALSE;", st->st_serialno, __FUNCTION__, __LINE__)); st->st_calculating = FALSE; finish_dh_secretiv(st, r); e = aggr_inR1_outI2_tail(md, NULL); if (dh->dh_md != NULL) { complete_v1_state_transition(&dh->dh_md, e); release_any_md(&dh->dh_md); } reset_cur_state(); } static void aggr_inR1_outI2_continue(struct adns_continuation *cr, err_t ugh) { key_continue(cr, ugh, aggr_inR1_outI2_tail); } static stf_status aggr_inR1_outI2_tail(struct msg_digest *md, struct key_continuation *kc) { struct state *const st = md->st; struct connection *c = st->st_connection; int auth_payload; /* HASH_R or SIG_R in */ { stf_status r = aggr_id_and_auth(md, TRUE, aggr_inR1_outI2_continue, kc); if (r != STF_OK) return r; } auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG; /**************** build output packet: HDR, HASH_I/SIG_I **************/ /* make sure HDR is at start of a clean buffer */ zero(&reply_buffer); init_pbs(&reply_stream, reply_buffer, sizeof(reply_buffer), "reply packet"); /* HDR out */ { struct isakmp_hdr r_hdr = md->hdr; memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); /* outputting should back-patch previous struct/hdr with payload type */ r_hdr.isa_np = auth_payload; r_hdr.isa_flags |= ISAKMP_FLAG_ENCRYPTION; /* KLUDGE */ if (!out_struct(&r_hdr, &isakmp_hdr_desc, &reply_stream, &md->rbody)) return STF_INTERNAL_ERROR; } if (st->hidden_variables.st_nat_traversal != LEMPTY) { if (!nat_traversal_add_natd(auth_payload, &md->rbody, md)) return STF_INTERNAL_ERROR; } /* HASH_I or SIG_I out */ { u_char idbuf[1024]; /* fits all possible identity payloads? */ struct isakmp_ipsec_id id_hd; chunk_t id_b; pb_stream id_pbs; u_char hash_val[MAX_DIGEST_LEN]; size_t hash_len; build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this); init_pbs(&id_pbs, idbuf, sizeof(idbuf), "identity payload"); id_hd.isaiid_np = ISAKMP_NEXT_NONE; if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &id_pbs, NULL) || !out_chunk(id_b, &id_pbs, "my identity")) return STF_INTERNAL_ERROR; hash_len = main_mode_hash(st, hash_val, TRUE, &id_pbs); if (auth_payload == ISAKMP_NEXT_HASH) { /* HASH_I out */ if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody, hash_val, hash_len, "HASH_I")) return STF_INTERNAL_ERROR; } else { /* SIG_I out */ u_char sig_val[RSA_MAX_OCTETS]; size_t sig_len = RSA_sign_hash(st->st_connection, sig_val, hash_val, hash_len); if (sig_len == 0) { loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature"); return STF_FAIL + AUTHENTICATION_FAILED; } if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc, &md->rbody, sig_val, sig_len, "SIG_I")) return STF_INTERNAL_ERROR; } } /* RFC2408 says we must encrypt at this point */ /* st_new_iv was computed by generate_skeyids_iv (??? DOESN'T EXIST) */ if (!encrypt_message(&md->rbody, st)) return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ /* It seems as per Cisco implementation, XAUTH and MODECFG * are not supposed to be performed again during rekey */ if (c->newest_isakmp_sa != SOS_NOBODY && st->st_connection->spd.this.xauth_client && st->st_connection->remotepeertype == CISCO) { DBG(DBG_CONTROL, DBG_log("Skipping XAUTH for rekey for Cisco Peer compatibility.")); st->hidden_variables.st_xauth_client_done = TRUE; st->st_oakley.doing_xauth = FALSE; if (st->st_connection->spd.this.modecfg_client) { DBG(DBG_CONTROL, DBG_log("Skipping XAUTH for rekey for Cisco Peer compatibility.")); st->hidden_variables.st_modecfg_vars_set = TRUE; st->hidden_variables.st_modecfg_started = TRUE; } } if (c->newest_isakmp_sa != SOS_NOBODY && st->st_connection->spd.this.xauth_client && st->st_connection->remotepeertype == CISCO) { DBG(DBG_CONTROL, DBG_log("This seems to be rekey, and XAUTH is not supposed to be done again")); st->hidden_variables.st_xauth_client_done = TRUE; st->st_oakley.doing_xauth = FALSE; if (st->st_connection->spd.this.modecfg_client) { DBG(DBG_CONTROL, DBG_log("This seems to be rekey, and MODECFG is not supposed to be done again")); st->hidden_variables.st_modecfg_vars_set = TRUE; st->hidden_variables.st_modecfg_started = TRUE; } } c->newest_isakmp_sa = st->st_serialno; /* save last IV from phase 1 so it can be restored later so anything * between the end of phase 1 and the start of phase 2 i.e. mode config * payloads etc. will not lose our IV */ set_ph1_iv_from_new(st); return STF_OK; } /* STATE_AGGR_R1: HDR*, HASH_I --> done */ static stf_status aggr_inI2_tail(struct msg_digest *md, struct key_continuation *kc); /* forward */ static void aggr_inI2_continue(struct adns_continuation *cr, err_t ugh) { key_continue(cr, ugh, aggr_inI2_tail); } stf_status aggr_inI2(struct msg_digest *md) { return aggr_inI2_tail(md, NULL); } static stf_status aggr_inI2_tail(struct msg_digest *md, struct key_continuation *kc) { struct state *const st = md->st; struct connection *c = st->st_connection; u_char idbuf[1024]; /* ??? enough room for reconstructed peer ID payload? */ struct payload_digest id_pd; ikev1_natd_init(st, md); /* Reconstruct the peer ID so the peer hash can be authenticated */ { struct isakmp_ipsec_id id_hd; chunk_t id_b; pb_stream pbs; pb_stream id_pbs; build_id_payload(&id_hd, &id_b, &st->st_connection->spd.that); init_pbs(&pbs, idbuf, sizeof(idbuf), "identity payload"); id_hd.isaiid_np = ISAKMP_NEXT_NONE; /* interop ID for SoftRemote & maybe others ? */ id_hd.isaiid_protoid = st->st_peeridentity_protocol; id_hd.isaiid_port = htons(st->st_peeridentity_port); if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &pbs, &id_pbs) || !out_chunk(id_b, &id_pbs, "my identity")) return STF_INTERNAL_ERROR; close_output_pbs(&id_pbs); id_pbs.roof = pbs.cur; id_pbs.cur = pbs.start; if (!in_struct(&id_pd.payload, &isakmp_identification_desc, &id_pbs, &id_pd.pbs)) return STF_FAIL + PAYLOAD_MALFORMED; } md->chain[ISAKMP_NEXT_ID] = &id_pd; /* HASH_I or SIG_I in */ { stf_status r = aggr_id_and_auth(md, FALSE, aggr_inI2_continue, kc); if (r != STF_OK) return r; } /* And reset the md to not leave stale pointers to our private id payload */ md->chain[ISAKMP_NEXT_ID] = NULL; /**************** done input ****************/ /* It seems as per Cisco implementation, XAUTH and MODECFG * are not supposed to be performed again during rekey */ if (c->newest_isakmp_sa != SOS_NOBODY && st->st_connection->spd.this.xauth_client && st->st_connection->remotepeertype == CISCO) { DBG(DBG_CONTROL, DBG_log("Skipping XAUTH for rekey for Cisco Peer compatibility.")); st->hidden_variables.st_xauth_client_done = TRUE; st->st_oakley.doing_xauth = FALSE; if (st->st_connection->spd.this.modecfg_client) { DBG(DBG_CONTROL, DBG_log("Skipping ModeCFG for rekey for Cisco Peer compatibility.")); st->hidden_variables.st_modecfg_vars_set = TRUE; st->hidden_variables.st_modecfg_started = TRUE; } } if (c->newest_isakmp_sa != SOS_NOBODY && st->st_connection->spd.this.xauth_client && st->st_connection->remotepeertype == CISCO) { DBG(DBG_CONTROL, DBG_log("This seems to be rekey, and XAUTH is not supposed to be done again")); st->hidden_variables.st_xauth_client_done = TRUE; st->st_oakley.doing_xauth = FALSE; if (st->st_connection->spd.this.modecfg_client) { DBG(DBG_CONTROL, DBG_log("This seems to be rekey, and MODECFG is not supposed to be done again")); st->hidden_variables.st_modecfg_vars_set = TRUE; st->hidden_variables.st_modecfg_started = TRUE; } } c->newest_isakmp_sa = st->st_serialno; update_iv(st); /* Finalize our Phase 1 IV */ /* save last IV from phase 1 so it can be restored later so anything * between the end of phase 1 and the start of phase 2 i.e. mode config * payloads etc. will not lose our IV */ set_ph1_iv_from_new(st); DBG(DBG_CONTROL, DBG_log("phase 1 complete")); return STF_OK; } /* * Initiate an Oakley Aggressive Mode exchange. * --> HDR, SA, KE, Ni, IDii */ static stf_status aggr_outI1_tail(struct pluto_crypto_req_cont *pcrc, struct pluto_crypto_req *r); /* forward */ static void aggr_outI1_continue(struct pluto_crypto_req_cont *pcrc, struct pluto_crypto_req *r, err_t ugh) { struct ke_continuation *ke = (struct ke_continuation *)pcrc; struct msg_digest *md = ke->ke_md; struct state *const st = md->st; stf_status e; DBG(DBG_CONTROL, DBG_log("aggr_outI1_continue for #%lu: calculated ke+nonce, sending I1", ke->ke_pcrc.pcrc_serialno)); if (st == NULL) { loglog(RC_LOG_SERIOUS, "%s: Request was disconnected from state", __FUNCTION__); passert(ke->ke_pcrc.pcrc_serialno == SOS_NOBODY); /* transitional */ release_any_md(&ke->ke_md); return; } passert(ke->ke_pcrc.pcrc_serialno == st->st_serialno); /* transitional */ /* XXX should check out ugh */ passert(ugh == NULL); passert(cur_state == NULL); passert(st != NULL); passert(st->st_suspended_md == ke->ke_md); unset_suspended(st); /* no longer connected or suspended */ set_cur_state(st); DBG(DBG_CONTROLMORE, DBG_log("#%lu %s:%u st->st_calculating = FALSE;", st->st_serialno, __FUNCTION__, __LINE__)); st->st_calculating = FALSE; e = aggr_outI1_tail(pcrc, r); if (ke->ke_md != NULL) { complete_v1_state_transition(&ke->ke_md, e); release_any_md(&ke->ke_md); } reset_globals(); passert(GLOBALS_ARE_RESET()); } stf_status aggr_outI1(int whack_sock, struct connection *c, struct state *predecessor, lset_t policy, unsigned long try, enum crypto_importance importance #ifdef HAVE_LABELED_IPSEC , struct xfrm_user_sec_ctx_ike * uctx #endif ) { struct state *st; struct spd_route *sr; /* set up new state */ cur_state = st = new_state(); st->st_connection = c; #ifdef HAVE_LABELED_IPSEC st->sec_ctx = NULL; #endif set_state_ike_endpoints(st, c); extra_debugging(c); st->st_policy = policy & ~POLICY_IPSEC_MASK; st->st_whack_sock = whack_sock; st->st_try = try; change_state(st, STATE_AGGR_I1); get_cookie(TRUE, st->st_icookie, COOKIE_SIZE, &c->spd.that.host_addr); st->st_import = importance; for (sr = &c->spd; sr != NULL; sr = sr->next) { if (sr->this.xauth_client) { if (sr->this.xauth_name != NULL) { jam_str(st->st_xauth_username, sizeof(st->st_xauth_username), sr->this.xauth_name); break; } } } insert_state(st); /* needs cookies, connection, and msgid (0) */ if (!init_aggr_st_oakley(st, policy)) { /* * This is only the case if NO IKE proposal was specified in the * configuration file. It's not the case if there were multiple * configurations, even conflicting multiple DH groups. So this * should tell the user to add a proper proposal policy */ loglog(RC_AGGRALGO, "no IKE proposal policy specified in config! Can not initiate aggressive mode. A policy must be specified in the configuration and should contain at most one DH group (mod1024, mod1536, mod2048). Only the first DH group will be honored."); reset_globals(); return STF_FAIL; } if (HAS_IPSEC_POLICY(policy)) add_pending(dup_any(whack_sock), st, c, policy, 1, predecessor == NULL ? SOS_NOBODY : predecessor->st_serialno #ifdef HAVE_LABELED_IPSEC , uctx #endif ); if (predecessor == NULL) { libreswan_log( "initiating Aggressive Mode #%lu, connection \"%s\"", st->st_serialno, st->st_connection->name); } else { update_pending(predecessor, st); libreswan_log( "initiating Aggressive Mode #%lu to replace #%lu, connection \"%s\"", st->st_serialno, predecessor->st_serialno, st->st_connection->name); } { struct ke_continuation *ke = alloc_thing( struct ke_continuation, "aggr_outI1 KE"); stf_status e; ke->ke_md = alloc_md(); ke->ke_md->st = st; set_suspended(st, ke->ke_md); if (!st->st_sec_in_use) { /* need to calculate KE and Nonce */ pcrc_init(&ke->ke_pcrc, aggr_outI1_continue); e = build_ke(&ke->ke_pcrc, st, st->st_oakley.group, importance); } else { /* KE and Nonce already calculated */ ke->ke_pcrc.pcrc_serialno = st->st_serialno; /* transitional */ e = aggr_outI1_tail(&ke->ke_pcrc, NULL); } reset_globals(); return e; } } static stf_status aggr_outI1_tail(struct pluto_crypto_req_cont *pcrc, struct pluto_crypto_req *r) { struct ke_continuation *ke = (struct ke_continuation *)pcrc; struct msg_digest *md = ke->ke_md; struct state *const st = md->st; struct connection *c = st->st_connection; passert(ke->ke_pcrc.pcrc_serialno == st->st_serialno); /* transitional */ DBG(DBG_CONTROL, DBG_log("aggr_outI1_tail for #%lu", ke->ke_pcrc.pcrc_serialno)); /* the MD is already set up by alloc_md() */ /* make sure HDR is at start of a clean buffer */ zero(&reply_buffer); init_pbs(&reply_stream, reply_buffer, sizeof(reply_buffer), "reply packet"); /* HDR out */ { struct isakmp_hdr hdr; zero(&hdr); /* default to 0 */ hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; hdr.isa_np = ISAKMP_NEXT_SA; hdr.isa_xchg = ISAKMP_XCHG_AGGR; memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); /* R-cookie, flags and MessageID are left zero */ if (!out_struct(&hdr, &isakmp_hdr_desc, &reply_stream, &md->rbody)) { cur_state = NULL; return STF_INTERNAL_ERROR; } } /* SA out */ { u_char *sa_start = md->rbody.cur; if (!ikev1_out_sa(&md->rbody, &oakley_am_sadb[sadb_index(st->st_policy, c)], st, TRUE, TRUE, ISAKMP_NEXT_KE)) { cur_state = NULL; return STF_INTERNAL_ERROR; } /* save initiator SA for later HASH */ passert(st->st_p1isa.ptr == NULL); /* no leak! */ clonetochunk(st->st_p1isa, sa_start, md->rbody.cur - sa_start, "sa in aggr_outI1"); } /* KE out */ if (!ship_KE(st, r, &st->st_gi, &md->rbody, ISAKMP_NEXT_NONCE)) return STF_INTERNAL_ERROR; /* Ni out */ if (!ship_nonce(&st->st_ni, r, &md->rbody, ISAKMP_NEXT_ID, "Ni")) return STF_INTERNAL_ERROR; DBG(DBG_CONTROLMORE, DBG_log("setting sec: %d", st->st_sec_in_use)); /* IDii out */ { struct isakmp_ipsec_id id_hd; chunk_t id_b; pb_stream id_pbs; build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this); id_hd.isaiid_np = ISAKMP_NEXT_VID; if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &id_pbs) || !out_chunk(id_b, &id_pbs, "my identity")) return STF_INTERNAL_ERROR; close_output_pbs(&id_pbs); } int numvidtosend = 1; /* Always announce DPD capablity */ if (c->spd.this.xauth_client || c->spd.this.xauth_server) numvidtosend++; if (nat_traversal_enabled) numvidtosend++; if(c->cisco_unity) numvidtosend++; if(c->send_vendorid) numvidtosend++; if (c->policy & POLICY_IKE_FRAG_ALLOW) numvidtosend++; /* ALWAYS Announce our ability to do Dead Peer Detection to the peer */ { int np = --numvidtosend > 0 ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE; if (!out_vid(np, &md->rbody, VID_MISC_DPD)) return STF_INTERNAL_ERROR; } if (nat_traversal_enabled) { int np = --numvidtosend > 0 ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE; if (!nat_traversal_insert_vid(np, &md->rbody, st)) { reset_cur_state(); return STF_INTERNAL_ERROR; } } if (c->spd.this.xauth_client || c->spd.this.xauth_server) { int np = --numvidtosend > 0 ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE; if (!out_vid(np, &md->rbody, VID_MISC_XAUTH)) return STF_INTERNAL_ERROR; } if(c->cisco_unity) { int np = --numvidtosend > 0 ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE; if (!out_vid(np, &md->rbody, VID_CISCO_UNITY)) return STF_INTERNAL_ERROR; } if(c->send_vendorid) { int np = --numvidtosend > 0 ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE; if (!out_vid(np, &md->rbody, VID_LIBRESWANSELF)) return STF_INTERNAL_ERROR; } if (c->policy & POLICY_IKE_FRAG_ALLOW) { int np = --numvidtosend > 0 ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE; if (!out_vid(np, &md->rbody, VID_IKE_FRAGMENTATION)) return STF_INTERNAL_ERROR; } /* INITIAL_CONTACT is an authenticated message, no VID here */ passert(numvidtosend == 0); /* finish message */ if (!close_message(&md->rbody, st)) return STF_INTERNAL_ERROR; close_output_pbs(&reply_stream); /* let TCL hack it before we mark the length and copy it */ clonetochunk(st->st_tpacket, reply_stream.start, pbs_offset(&reply_stream), "reply packet from aggr_outI1"); /* Transmit */ DBG_cond_dump(DBG_RAW, "sending:\n", st->st_tpacket.ptr, st->st_tpacket.len); send_ike_msg(st, "aggr_outI1"); /* Set up a retransmission event, half a minute hence */ delete_event(st); event_schedule(EVENT_v1_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); whack_log(RC_NEW_STATE + STATE_AGGR_I1, "%s: initiate", enum_name(&state_names, st->st_state)); cur_state = NULL; return STF_IGNORE; }