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 + -
显示快捷键?