diff -ruN freeswan-1.5.orig/pluto/ipsec_doi.c freeswan-1.5/pluto/ipsec_doi.c --- freeswan-1.5.orig/pluto/ipsec_doi.c Wed Jun 21 14:24:32 2000 +++ freeswan-1.5/pluto/ipsec_doi.c Thu Oct 5 09:08:12 2000 @@ -53,6 +53,15 @@ #define RETURN_STF_FAILURE(f) \ { int r = (f); if (r != NOTHING_WRONG) return STF_FAIL + r; } +stf_status send_delete(struct state *p2st, ipsec_spi_t *spi, bool ESP); +static bool encrypt_message(pb_stream *pbs, struct state *st); + +/* needed for PGPnet Vendor ID */ +char pgp_vid[] = { 0x4f, 0x70, 0x65, 0x6e, + 0x50, 0x47, 0x50, 0x31, + 0x30, 0x31, 0x37, 0x31}; + + /* if we haven't already done so, compute a local DH secret (st->st_sec) and * the corresponding public value (g). This is emitted as a KE payload. */ @@ -257,6 +266,121 @@ // } //} #endif /* not currently used */ + + + stf_status + send_delete(struct state *p2st, ipsec_spi_t *spi, bool ESP) + { + + pb_stream reply_pbs; + pb_stream r_hdr_pbs; + msgid_t msgid; + u_char old_new_iv[MAX_DIGEST_LEN]; + u_char old_iv[MAX_DIGEST_LEN]; + u_char buffer[8192]; + struct state *p1st; + + u_char spilen = sizeof(ipsec_spi_t); + u_char + *r_hashval, /* where in reply to jam hash value */ + *r_hash_start; /* start of what is to be hashed */ + + memset(buffer, '\0', sizeof(buffer)); + init_pbs(&reply_pbs, buffer, sizeof(buffer), "delete msg"); + + /* find the related P1-State to the calling P2-state */ + p1st = find_state(p2st->st_icookie, p2st->st_rcookie, + p2st->st_connection->that.host_addr, 0); + if (p1st == NULL) + { + DBG_log("no phase 1 state where one should be"); + return STF_INTERNAL_ERROR; + } + + msgid = generate_msgid(p1st); + + /* 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)) + return STF_INTERNAL_ERROR; + } + + /* HASH -- space to be filled later */ + { + pb_stream hash_pbs; + + if (!out_generic(ISAKMP_NEXT_D, &isakmp_hash_desc, &r_hdr_pbs, &hash_pbs)) + return STF_INTERNAL_ERROR; + r_hashval = hash_pbs.cur; /* remember where to plant value */ + if (!out_zero(p1st->st_oakley.hasher->hash_digest_len, &hash_pbs, "HASH(1)")) + return STF_INTERNAL_ERROR; + close_output_pbs(&hash_pbs); + r_hash_start = r_hdr_pbs.cur; /* hash from after HASH(1) */ + } + + /* DELETE PAYLOAD */ + { + pb_stream del_pbs; + struct isakmp_delete isad; + + isad.isad_doi = ISAKMP_DOI_IPSEC; + isad.isad_np = ISAKMP_NEXT_NONE; + isad.isad_spisize = spilen; + if (ESP) isad.isad_protoid = PROTO_IPSEC_ESP; + else isad.isad_protoid = PROTO_IPSEC_AH; + isad.isad_nospi = 0x0001; + if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs)) + return STF_INTERNAL_ERROR; + if (!out_raw(spi, spilen, &del_pbs, "delete payload")) + return STF_INTERNAL_ERROR;; + close_output_pbs(&del_pbs); + } + + { + 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)); + } + + /* save old IV (this prevents from copying a whole new state object + * for NOTIFICATION / DELETE messages we don't need to maintain a state + * because there are no retransmissions... + */ + + memcpy(old_new_iv, p1st->st_new_iv, p1st->st_new_iv_len); + memcpy(old_iv, p1st->st_iv, p1st->st_iv_len); + init_phase2_iv(p1st, &msgid); + + if(!encrypt_message(&r_hdr_pbs, p1st)) passert(FALSE); + + clonetochunk(p1st->st_tpacket, reply_pbs.start, pbs_offset(&reply_pbs) + , "reply packet for main_outI1"); + + send_packet(p1st, "delete notify"); + + /* get back old IV for this state */ + memcpy(p1st->st_new_iv, old_new_iv, p1st->st_new_iv_len); + memcpy(p1st->st_iv, old_iv, p1st->st_iv_len); + + return STF_IGNORE; +} + + /* The whole message must be a multiple of 4 octets. * I'm not sure where this is spelled out, but look at diff -ruN freeswan-1.5.orig/pluto/kernel.c freeswan-1.5/pluto/kernel.c --- freeswan-1.5.orig/pluto/kernel.c Wed Jun 21 14:24:33 2000 +++ freeswan-1.5/pluto/kernel.c Thu Oct 5 09:08:12 2000 @@ -48,6 +48,7 @@ #include "server.h" #include "whack.h" /* for RC_LOG_SERIOUS */ +extern int send_delete(struct state *st, ipsec_spi_t *spi, bool ESP); bool no_klips = FALSE; /* don't actually use KLIPS */ @@ -1003,6 +1004,8 @@ { passert(FALSE); /* neither AH nor ESP in outbound SA bundle! */ } + + send_delete(st, &f->our_spi, proto==SA_ESP?TRUE:FALSE); return inbound ? del_spi(f->our_spi, proto, c->that.host_addr, c->this.host_addr)