📄 ipsec_doi.c
字号:
r_hash_start = r_hdr_pbs.cur; /* hash from after HASH(1) */ } /* Notification Payload */ { pb_stream not_pbs; struct isakmp_notification isan; isan.isan_doi = ISAKMP_DOI_IPSEC; isan.isan_np = ISAKMP_NEXT_NONE; isan.isan_type = type; isan.isan_spisize = spisize; isan.isan_protoid = protoid; if (!out_struct(&isan, &isakmp_notification_desc, &r_hdr_pbs, ¬_pbs) || !out_raw(spi, spisize, ¬_pbs, "spi")) impossible(); close_output_pbs(¬_pbs); } /* calculate hash value and patch into Hash Payload */ if (encst) { struct hmac_ctx ctx; hmac_init_chunk(&ctx, encst->st_oakley.hasher, encst->st_skeyid_a); hmac_update(&ctx, (u_char *) &msgid, sizeof(msgid_t)); hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur-r_hash_start); hmac_final(r_hashval, &ctx); DBG(DBG_CRYPT, DBG_log("HASH(1) computed:"); DBG_dump("", r_hashval, ctx.hmac_digest_len); ) } /* Encrypt message (preserve st_iv) */ if (encst) { u_char old_iv[MAX_DIGEST_LEN]; u_int old_iv_len = encst->st_iv_len; if (old_iv_len > MAX_DIGEST_LEN) impossible(); memcpy(old_iv, encst->st_iv, old_iv_len); if (!IS_ISAKMP_SA_ESTABLISHED(encst->st_state)) { if (encst->st_new_iv_len > MAX_DIGEST_LEN) impossible(); memcpy(encst->st_iv, encst->st_new_iv, encst->st_new_iv_len); encst->st_iv_len = encst->st_new_iv_len; } init_phase2_iv(encst, &msgid); if (!encrypt_message(&r_hdr_pbs, encst)) impossible(); /* restore preserved st_iv*/ memcpy(encst->st_iv, old_iv, old_iv_len); encst->st_iv_len = old_iv_len; } else { close_output_pbs(&r_hdr_pbs); } /* Send packet (preserve st_tpacket) */ { chunk_t saved_tpacket = sndst->st_tpacket; setchunk(sndst->st_tpacket, pbs.start, pbs_offset(&pbs)); send_packet(sndst, "notification packet"); sndst->st_tpacket = saved_tpacket; }}voidsend_notification_from_state(struct state *st, enum state_kind state, u_int16_t type){ struct state *p1st; passert(st); if (state == STATE_UNDEFINED) state = st->st_state; if (IS_QUICK(state)) { p1st = find_phase1_state(st->st_connection, ISAKMP_SA_ESTABLISHED_STATES); if ((p1st == NULL) || (!IS_ISAKMP_SA_ESTABLISHED(p1st->st_state))) { loglog(RC_LOG_SERIOUS, "no Phase1 state for Quick mode notification"); return; } send_notification(st, type, p1st, generate_msgid(p1st), st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP); } else if (IS_ISAKMP_ENCRYPTED(state)) { send_notification(st, type, st, generate_msgid(st), st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP); } else { /* no ISAKMP SA established - don't encrypt notification */ send_notification(st, type, NULL, 0, st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP); }}voidsend_notification_from_md(struct msg_digest *md, u_int16_t type){ /** * Create a dummy state to be able to use send_packet in * send_notification * * we need to set: * st_connection->that.host_addr * st_connection->that.host_port * st_connection->interface */ struct state st; struct connection cnx; passert(md); memset(&st, 0, sizeof(st)); memset(&cnx, 0, sizeof(cnx)); st.st_connection = &cnx; cnx.spd.that.host_addr = md->sender; cnx.spd.that.host_port = md->sender_port; cnx.interface = md->iface; send_notification(&st, type, NULL, 0, md->hdr.isa_icookie, md->hdr.isa_rcookie, NULL, 0, PROTO_ISAKMP);}/** Send a Delete Notification to announce deletion of ISAKMP SA or * inbound IPSEC SAs. Does nothing if no such SAs are being deleted. * Delete Notifications cannot announce deletion of outbound IPSEC/ISAKMP SAs. * * @param st State struct (hopefully has some SA's related to it) */voidsend_delete(struct state *st){ pb_stream reply_pbs; pb_stream r_hdr_pbs; msgid_t msgid; u_char buffer[8192]; struct state *p1st; ip_said said[EM_MAXRELSPIS]; ip_said *ns = said; u_char *r_hashval, /* where in reply to jam hash value */ *r_hash_start; /* start of what is to be hashed */ bool isakmp_sa = FALSE; /* If there are IPsec SA's related to this state struct... */ if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) { /* Find their phase1 state object */ p1st = find_phase1_state(st->st_connection, ISAKMP_SA_ESTABLISHED_STATES); if (p1st == NULL) { DBG(DBG_CONTROL, DBG_log("no Phase 1 state for Delete")); return; } if (st->st_ah.present) { ns->spi = st->st_ah.our_spi; ns->dst = st->st_connection->spd.this.host_addr; ns->proto = PROTO_IPSEC_AH; ns++; } if (st->st_esp.present) { ns->spi = st->st_esp.our_spi; ns->dst = st->st_connection->spd.this.host_addr; ns->proto = PROTO_IPSEC_ESP; ns++; } passert(ns != said); /* there must be some SAs to delete */ } /* or ISAKMP SA's... */ else if (IS_ISAKMP_SA_ESTABLISHED(st->st_state)) { p1st = st; isakmp_sa = TRUE; } else { return; /* nothing to do */ } msgid = generate_msgid(p1st); zero(buffer); init_pbs(&reply_pbs, buffer, sizeof(buffer), "delete msg"); /* HDR* */ { struct isakmp_hdr hdr; hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; hdr.isa_np = ISAKMP_NEXT_HASH; hdr.isa_xchg = ISAKMP_XCHG_INFO; hdr.isa_msgid = msgid; hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; memcpy(hdr.isa_icookie, p1st->st_icookie, COOKIE_SIZE); memcpy(hdr.isa_rcookie, p1st->st_rcookie, COOKIE_SIZE); if (!out_struct(&hdr, &isakmp_hdr_desc, &reply_pbs, &r_hdr_pbs)) impossible(); } /* HASH -- value to be filled later */ { pb_stream hash_pbs; if (!out_generic(ISAKMP_NEXT_D, &isakmp_hash_desc, &r_hdr_pbs, &hash_pbs)) impossible(); r_hashval = hash_pbs.cur; /* remember where to plant value */ if (!out_zero(p1st->st_oakley.hasher->hash_digest_len, &hash_pbs, "HASH(1)")) impossible(); close_output_pbs(&hash_pbs); r_hash_start = r_hdr_pbs.cur; /* hash from after HASH(1) */ } /* Delete Payloads */ if (isakmp_sa) { pb_stream del_pbs; struct isakmp_delete isad; u_char isakmp_spi[2*COOKIE_SIZE]; isad.isad_doi = ISAKMP_DOI_IPSEC; isad.isad_np = ISAKMP_NEXT_NONE; isad.isad_spisize = (2 * COOKIE_SIZE); isad.isad_protoid = PROTO_ISAKMP; isad.isad_nospi = 1; memcpy(isakmp_spi, st->st_icookie, COOKIE_SIZE); memcpy(isakmp_spi+COOKIE_SIZE, st->st_rcookie, COOKIE_SIZE); if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs) || !out_raw(&isakmp_spi, (2*COOKIE_SIZE), &del_pbs, "delete payload")) impossible(); close_output_pbs(&del_pbs); } else { while (ns != said) { pb_stream del_pbs; struct isakmp_delete isad; ns--; isad.isad_doi = ISAKMP_DOI_IPSEC; isad.isad_np = ns == said? ISAKMP_NEXT_NONE : ISAKMP_NEXT_D; isad.isad_spisize = sizeof(ipsec_spi_t); isad.isad_protoid = ns->proto; isad.isad_nospi = 1; if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs) || !out_raw(&ns->spi, sizeof(ipsec_spi_t), &del_pbs, "delete payload")) impossible(); close_output_pbs(&del_pbs); } } /* calculate hash value and patch into Hash Payload */ { struct hmac_ctx ctx; hmac_init_chunk(&ctx, p1st->st_oakley.hasher, p1st->st_skeyid_a); hmac_update(&ctx, (u_char *) &msgid, sizeof(msgid_t)); hmac_update(&ctx, r_hash_start, r_hdr_pbs.cur-r_hash_start); hmac_final(r_hashval, &ctx); DBG(DBG_CRYPT, DBG_log("HASH(1) computed:"); DBG_dump("", r_hashval, ctx.hmac_digest_len); ) } /* Do a dance to avoid needing a new state object. * We use the Phase 1 State. This is the one with right * IV, for one thing. * The tricky bits are: * - we need to preserve (save/restore) st_iv (but not st_iv_new) * - we need to preserve (save/restore) st_tpacket. */ { u_char old_iv[MAX_DIGEST_LEN]; chunk_t saved_tpacket = p1st->st_tpacket; save_iv(p1st, old_iv); init_phase2_iv(p1st, &msgid); if (!encrypt_message(&r_hdr_pbs, p1st)) impossible(); setchunk(p1st->st_tpacket, reply_pbs.start, pbs_offset(&reply_pbs)); send_packet(p1st, "delete notify"); p1st->st_tpacket = saved_tpacket; /* get back old IV for this state */ set_iv(p1st, old_iv); }}/** Accept a Delete SA notification, and process it if valid. * * @param st State structure * @param md Message Digest * @param p Payload digest */voidaccept_delete(struct state *st, struct msg_digest *md, struct payload_digest *p){ struct isakmp_delete *d = &(p->payload.delete); size_t sizespi; int i; /* We only listen to encrypted notifications */ if (!md->encrypted) { loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: not encrypted"); return; } /* If there is no SA related to this request, but it was encrypted */ if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) { /* can't happen (if msg is encrypt), but just to be sure */ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " "ISAKMP SA not established"); return; } if (d->isad_nospi == 0) { loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: no SPI"); return; } switch (d->isad_protoid) { case PROTO_ISAKMP: sizespi = 2 * COOKIE_SIZE; break; case PROTO_IPSEC_AH: case PROTO_IPSEC_ESP: sizespi = sizeof(ipsec_spi_t); break; case PROTO_IPCOMP: /* nothing interesting to delete */ return; default: loglog(RC_LOG_SERIOUS , "ignoring Delete SA payload: unknown Protocol ID (%s)" , enum_show(&protocol_names, d->isad_protoid)); return; } if (d->isad_spisize != sizespi) { loglog(RC_LOG_SERIOUS , "ignoring Delete SA payload: bad SPI size (%d) for %s" , d->isad_spisize, enum_show(&protocol_names, d->isad_protoid)); return; } if (pbs_left(&p->pbs) != d->isad_nospi * sizespi) { loglog(RC_LOG_SERIOUS , "ignoring Delete SA payload: invalid payload size"); return; } for (i = 0; i < d->isad_nospi; i++) { u_char *spi = p->pbs.cur + (i * sizespi); if (d->isad_protoid == PROTO_ISAKMP) { /** * ISAKMP */ struct state *dst = find_state(spi /*iCookie*/ , spi+COOKIE_SIZE /*rCookie*/ , &st->st_connection->spd.that.host_addr , MAINMODE_MSGID); if (dst == NULL) { loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " "ISAKMP SA not found (maybe expired)"); } else if (!same_peer_ids(st->st_connection, dst->st_connection, NULL)) { /* we've not authenticated the relevant identities */ loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " "ISAKMP SA used to convey Delete has different IDs from ISAKMP SA it deletes"); } else { struct connection *oldc; oldc = cur_connection; set_cur_connection(dst->st_connection);#ifdef NAT_TRAVERSAL if (nat_traversal_enabled) { nat_traversal_change_port_lookup(md, dst); }#endif loglog(RC_LOG_SERIOUS, "received Delete SA payload: " "deleting ISAKMP State #%lu", dst->st_serialno); delete_state(dst); set_cur_connection(oldc); } } else { /** * IPSEC (ESP/AH) */ bool bogus; struct state *dst = find_phase2_state_to_delete(st , d->isad_protoid , *(ipsec_spi_t *)spi /* network order */ , &bogus); if (dst == NULL) { loglog(RC_LOG_SERIOUS , "ignoring Delete SA payload: %s SA(0x%08lx) not found (%s)" , enum_show(&protocol_names, d->isad_protoid) , (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi) , bogus ? "our SPI - bogus implementation" : "maybe expired"); } else { struct connection *rc = dst->st_connection; struct connection *oldc; oldc = cur_connection; set_cur_connection(rc);#ifdef NAT_TRAVERSAL if (nat_traversal_enabled) { nat_traversal_change_port_lookup(md, dst); }#endif if (rc->newest_ipsec_sa == dst->st_serialno && (rc->policy & POLICY_UP)) { /* Last IPSec SA for a permanent connection that we * have initiated. Replace it in a few seconds. * * Useful if the other peer is rebooting. */#define DELETE_SA_DELAY EVENT_RETRANSMIT_DELAY_0 if (dst->st_event != NULL && dst->st_event->ev_type == EVENT_SA_REPLACE && dst->st_event->ev_time <= DELETE_SA_DELAY + now()) { /* Patch from Angus Lees to ignore retransmited * Delete SA. */ loglog(RC_LOG_SERIOUS, "received Delete SA payload: "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -