ikev1_quick.c
来自「ipsec vpn」· C语言 代码 · 共 2,176 行 · 第 1/4 页
C
2,176 行
* and filling in a few more details. * We used to include gateways_from_dns, but that * seems pointless at this stage of negotiation. * We should record DNS sec use, if any -- belongs in * state during perhaps. */ p = oppo_instantiate(p, &c->spd.that.host_addr, &c->spd.that.id , NULL, &our_client, &his_client); } else { /* Plain Road Warrior: * instantiate, carrying over authenticated peer ID */ p = rw_instantiate(p, &c->spd.that.host_addr, his_net, &c->spd.that.id); } }#ifdef DEBUG /* temporarily bump up cur_debugging to get "using..." message * printed if we'd want it with new connection. */ { lset_t old_cur_debugging = cur_debugging; set_debugging(cur_debugging | p->extra_debugging); DBG(DBG_CONTROL, DBG_log("using connection \"%s\"", p->name)); set_debugging(old_cur_debugging); }#endif c = p; } /* fill in the client's true ip address/subnet */ if (p->spd.that.has_client_wildcard) { p->spd.that.client = *his_net; p->spd.that.has_client_wildcard = FALSE; } /* fill in the client's true port */ if (p->spd.that.has_port_wildcard) { int port = htons(b->his.port); setportof(port, &p->spd.that.host_addr); setportof(port, &p->spd.that.client.addr); p->spd.that.port = b->his.port; p->spd.that.has_port_wildcard = FALSE; }#ifdef VIRTUAL_IP else if (is_virtual_connection(c)) { c->spd.that.client = *his_net; c->spd.that.virt = NULL; if (subnetishost(his_net) && addrinsubnet(&c->spd.that.host_addr, his_net)) c->spd.that.has_client = FALSE; }#endif } passert((p1st->st_policy & POLICY_PFS)==0 || p1st->st_pfs_group != NULL ); /* now that we are sure of our connection, create our new state, and * do any asynchronous cryptographic operations that we may need to * make it all work. */ /* now that we are sure of our connection, create our new state */ { struct state *const st = duplicate_state(p1st); /* first: fill in missing bits of our new state object * note: we don't copy over st_peer_pubkey, the public key * that authenticated the ISAKMP SA. We only need it in this * routine, so we can "reach back" to p1st to get it. */ if (st->st_connection != c) { struct connection *t = st->st_connection; st->st_connection = c; set_cur_connection(c); connection_discard(t); } st->st_try = 0; /* not our job to try again from start */ st->st_msgid = md->hdr.isa_msgid; st->st_new_iv_len = b->new_iv_len; set_new_iv(st, b->new_iv); set_cur_state(st); /* (caller will reset) */ md->st = st; /* feed back new state */ st->st_peeruserprotoid = b->his.proto; st->st_peeruserport = b->his.port; st->st_myuserprotoid = b->my.proto; st->st_myuserport = b->my.port; st->st_state = STATE_QUICK_R0; insert_state(st); /* needs cookies, connection, and msgid */ /* copy the connection's * IPSEC policy into our state. The ISAKMP policy is water under * the bridge, I think. It will reflect the ISAKMP SA that we * are using. */ st->st_policy = (p1st->st_policy & POLICY_ID_AUTH_MASK) | (c->policy & ~POLICY_ID_AUTH_MASK);#ifdef NAT_TRAVERSAL if (p1st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) { st->hidden_variables.st_nat_traversal = p1st->hidden_variables.st_nat_traversal; nat_traversal_change_port_lookup(md, md->st); } else { st->hidden_variables.st_nat_traversal = 0; } if ((st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) && (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATOA)) { nat_traversal_natoa_lookup(md); }#endif passert(st->st_connection != NULL); passert(st->st_connection == c); /* process SA in */ { struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA]; pb_stream in_pbs = sapd->pbs; /* parse and accept body, setting variables, but not forming * our reply. We'll make up the reply later on. * * note that we process the copy of the pbs, so that * we can process it again in the cryptotail(). */ st->st_pfs_group = &unset_group; RETURN_STF_FAILURE(parse_ipsec_sa_body(&in_pbs , &sapd->payload.sa , NULL , FALSE, st)); } /* Ni in */ RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni")); /* [ KE ] in (for PFS) */ RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gi , "Gi", "Quick Mode I1")); passert(st->st_pfs_group != &unset_group); passert(st->st_connection != NULL); { struct qke_continuation *qke = alloc_thing(struct qke_continuation , "quick_outI1 KE"); stf_status e; enum crypto_importance ci; ci = pcim_ongoing_crypto; if(ci < st->st_import) ci = st->st_import; qke->st = st; qke->isakmp_sa = p1st; qke->md = md; qke->qke_pcrc.pcrc_func = quick_inI1_outR1_cryptocontinue; if (st->st_pfs_group != NULL) { e = build_ke(&qke->qke_pcrc, st, st->st_pfs_group, ci); } else { e = build_nonce(&qke->qke_pcrc, st, ci); } passert(st->st_connection != NULL); return e; } }}static stf_statusquick_inI1_outR1_cryptotail(struct qke_continuation *qke , struct pluto_crypto_req *r){ struct msg_digest *md = qke->md; struct state *st = md->st; struct connection *c = st->st_connection; struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA]; struct isakmp_sa sa = sapd->payload.sa; pb_stream r_sa_pbs; u_char /* set by START_HASH_PAYLOAD: */ *r_hashval, /* where in reply to jam hash value */ *r_hash_start; /* from where to start hashing */ /* Start the output packet. * * proccess_packet() would automatically generate the HDR* * payload if smc->first_out_payload is not ISAKMP_NEXT_NONE. * We don't do this because we wish there to be no partially * built output packet if we need to suspend for asynch DNS. * * We build the reply packet as we parse the message since * the parse_ipsec_sa_body emits the reply SA */ /* HDR* out */ echo_hdr(md, TRUE, ISAKMP_NEXT_HASH); /* HASH(2) out -- first pass */ START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_SA); passert(st->st_connection == c); passert(st->st_connection != NULL); /* sa header is unchanged -- except for np */ sa.isasa_np = ISAKMP_NEXT_NONCE; if (!out_struct(&sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs)) return STF_INTERNAL_ERROR; /* parse and accept body, this time recording our reply */ RETURN_STF_FAILURE(parse_ipsec_sa_body(&sapd->pbs , &sapd->payload.sa , &r_sa_pbs , FALSE, st)); passert(st->st_pfs_group != &unset_group); if ((st->st_policy & POLICY_PFS) && st->st_pfs_group == NULL) { loglog(RC_LOG_SERIOUS, "we require PFS but Quick I1 SA specifies no GROUP_DESCRIPTION"); return STF_FAIL + NO_PROPOSAL_CHOSEN; /* ??? */ } openswan_log("responding to Quick Mode {msgid:%08x}", st->st_msgid); /**** finish reply packet: Nr [, KE ] [, IDci, IDcr ] ****/ { int np; if(st->st_pfs_group != NULL) { np = ISAKMP_NEXT_KE; } else if(id_pd != NULL) { np = ISAKMP_NEXT_ID; } else { np = ISAKMP_NEXT_NONE; } /* Nr out */ if (!ship_nonce(&st->st_nr, r, &md->rbody , np, "Nr")) return STF_INTERNAL_ERROR; } /* [ KE ] out (for PFS) */ if (st->st_pfs_group != NULL) { stf_status stat; if (!ship_KE(st, r, &st->st_gr , &md->rbody , id_pd != NULL? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE)) return STF_INTERNAL_ERROR; stat = perform_dh_secret(st, RESPONDER, st->st_pfs_group->group); if(stat != STF_OK) { return stat; } } /* [ IDci, IDcr ] out */ if (id_pd != NULL) { struct isakmp_ipsec_id *p = (void *)md->rbody.cur; /* UGH! */ if (!out_raw(id_pd->pbs.start, pbs_room(&id_pd->pbs), &md->rbody, "IDci")) return STF_INTERNAL_ERROR; p->isaiid_np = ISAKMP_NEXT_ID; p = (void *)md->rbody.cur; /* UGH! */ if (!out_raw(id_pd->next->pbs.start, pbs_room(&id_pd->next->pbs), &md->rbody, "IDcr")) return STF_INTERNAL_ERROR; p->isaiid_np = ISAKMP_NEXT_NONE; }#ifdef NAT_TRAVERSAL if ((st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) && (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TRANSPORT) && (c->spd.that.has_client)) { /** Remove client **/ addrtosubnet(&c->spd.that.host_addr, &c->spd.that.client); c->spd.that.has_client = FALSE; }#endif /* Compute reply HASH(2) and insert in output */ (void)quick_mode_hash12(r_hashval, r_hash_start, md->rbody.cur , st, &st->st_msgid, TRUE); /* Derive new keying material */ compute_keymats(st); /* Tell the kernel to establish the new inbound SA * (unless the commit bit is set -- which we don't support). * We do this before any state updating so that * failure won't look like success. */ if (!install_inbound_ipsec_sa(st)) return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ /* encrypt message, except for fixed part of header */ if (!encrypt_message(&md->rbody, st)) { delete_ipsec_sa(st, TRUE); return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ } DBG(DBG_CONTROLMORE, DBG_log("finished processing quick inI1")); return STF_OK;}/* Handle (the single) message from Responder in Quick Mode. * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] --> * HDR*, HASH(3) * (see RFC 2409 "IKE" 5.5) * Installs inbound and outbound IPsec SAs, routing, etc. */stf_statusquick_inR1_outI2(struct msg_digest *md){ struct state *const st = md->st; const struct connection *c = st->st_connection; /* HASH(2) in */ CHECK_QUICK_HASH(md , quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof , st, &st->st_msgid, TRUE) , "HASH(2)", "Quick R1"); /* SA in */ { struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; RETURN_STF_FAILURE(parse_ipsec_sa_body(&sa_pd->pbs , &sa_pd->payload.sa, NULL, TRUE, st)); } /* Nr in */ RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr")); /* [ KE ] in (for PFS) */ RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gr, "Gr", "Quick Mode R1")); if (st->st_pfs_group != NULL) { stf_status stat; stat = perform_dh_secret(st, INITIATOR, st->st_pfs_group->group); if(stat != STF_OK) { return stat; } } /* [ IDci, IDcr ] in; these must match what we sent */ { struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; if (id_pd != NULL) { /* ??? we are assuming IPSEC_DOI */ /* IDci (we are initiator) */ if (!check_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs , &st->st_myuserprotoid, &st->st_myuserport , &st->st_connection->spd.this.client , "our client")) return STF_FAIL + INVALID_ID_INFORMATION; /* IDcr (responder is peer) */ if (!check_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs , &st->st_peeruserprotoid, &st->st_peeruserport , &st->st_connection->spd.that.client , "peer client")) return STF_FAIL + INVALID_ID_INFORMATION; } else { /* no IDci, IDcr: we must check that the defaults match our proposal */ if (!subnetisaddr(&c->spd.this.client, &c->spd.this.host_addr) || !subnetisaddr(&c->spd.that.client, &c->spd.that.host_addr)) { loglog(RC_LOG_SERIOUS, "IDci, IDcr payloads missing in message" " but default does not match proposal"); return STF_FAIL + INVALID_ID_INFORMATION; } } }#ifdef NAT_TRAVERSAL if ((st->hidden_variables.st_nat_traversal & NAT_T_DETECTED) && (st->hidden_variables.st_nat_traversal & NAT_T_WITH_NATOA)) { nat_traversal_natoa_lookup(md); }#endif /* ??? We used to copy the accepted proposal into the state, but it was * never used. From sa_pd->pbs.start, length pbs_room(&sa_pd->pbs). */ /**************** build reply packet HDR*, HASH(3) ****************/ /* HDR* out done */ /* HASH(3) out -- since this is the only content, no passes needed */ { u_char /* set by START_HASH_PAYLOAD: */ *r_hashval, /* where in reply to jam hash value */ *r_hash_start; /* start of what is to be hashed */ START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_NONE); (void)quick_mode_hash3(r_hashval, st); } /* Derive new keying material */ compute_keymats(st); /* Tell the kernel to establish the inbound, outbound, and routing part * of the new SA (unless the commit bit is set -- which we don't support). * We do this before any state updating so that * failure won't look like success. */ if (!install_ipsec_sa(st, TRUE)) return STF_INTERNAL_ERROR; /* encrypt message, except for fixed part of header */ if (!encrypt_message(&md->rbody, st)) { delete_ipsec_sa(st, FALSE); return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ } { DBG(DBG_CONTROLMORE, DBG_log("inR1_outI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)" , st->st_connection->name , st->st_connection->instance_serial , st->st_serialno , st->st_connection->newest_ipsec_sa , st->st_connection->spd.eroute_owner)); } st->st_connection->newest_ipsec_sa = st->st_serialno; /* note (presumed) success */ if (c->gw_info != NULL) c->gw_info->key->last_worked_time = now(); /* If we have dpd delay and dpdtimeout set, then we are doing DPD on this conn, so initialize it */ if (st->st_connection->dpd_delay && st->st_connection->dpd_timeout) { if(dpd_init(st) != STF_OK) { delete_ipsec_sa(st, FALSE); return STF_FAIL; } } return STF_OK;}/* Handle last message of Quick Mode. * HDR*, HASH(3) -> done * (see RFC 2409 "IKE" 5.5) * Installs outbound IPsec SAs, routing, etc. */stf_statusquick_inI2(struct msg_digest *md){ struct state *const st = md->st; /* HASH(3) in */ CHECK_QUICK_HASH(md, quick_mode_hash3(hash_val, st) , "HASH(3)", "Quick I2"); /* Tell the kernel to establish the outbound and routing part of the new SA * (the previous state established inbound) * (unless the commit bit is set -- which we don't support). * We do this before any state updating so that * failure won't look like success. */ if (!install_ipsec_sa(st, FALSE)) return STF_INTERNAL_ERROR; { DBG(DBG_CONTROLMORE, DBG_log("inI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)" , st->st_connection->name , st->st_connection->instance_serial , st->st_serialno , st->st_connection->newest_ipsec_sa , st->st_connection->spd.eroute_owner)); } st->st_connection->newest_ipsec_sa = st->st_serialno; update_iv(st); /* not actually used, but tidy */ /* note (presumed) success */ { struct gw_info *gw = st->st_connection->gw_info; if (gw != NULL) gw->key->last_worked_time = now(); } /* If we have dpd delay and dpdtimeout set, then we are doing DPD on this conn, so initialize it */ if(st->st_connection->dpd_delay && st->st_connection->dpd_timeout) { if(dpd_init(st) != STF_OK) { delete_ipsec_sa(st, FALSE); return STF_FAIL; } } return STF_OK;}/* * Local Variables: * c-basic-offset:4 * c-style: pluto * End: */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?