Apply by doing:
        cd /usr/src
        patch -p0 < 014_isakmpd.patch

Then rebuild and install isakmpd:
        cd sbin/isakmpd
        make clean
        make depend
        make
        make install

Index: sbin/isakmpd/exchange.c
===================================================================
RCS file: /cvs/src/sbin/isakmpd/exchange.c,v
retrieving revision 1.78
retrieving revision 1.78.2.1
diff -u -p -r1.78 -r1.78.2.1
--- sbin/isakmpd/exchange.c	6 Mar 2003 13:32:42 -0000	1.78
+++ sbin/isakmpd/exchange.c	16 Jan 2004 00:00:21 -0000	1.78.2.1
@@ -225,8 +225,10 @@ exchange_validate (struct message *msg)
 	      && !TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_HASH])
 	      && !TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SIG]))
 	  || (*pc == EXCHANGE_SCRIPT_INFO
-	      && !TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_NOTIFY])
-	      && !TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_DELETE])))
+	      && ((!TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_NOTIFY])
+		   && !TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_DELETE]))
+	          || (TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_DELETE])
+		      && !TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_HASH])))))
 	{
 	  /* Missing payload.  */
 	  LOG_DBG ((LOG_MESSAGE, 70,
Index: sbin/isakmpd/ipsec.c
===================================================================
RCS file: /cvs/src/sbin/isakmpd/ipsec.c,v
retrieving revision 1.72.2.1
retrieving revision 1.72.2.2
diff -u -p -r1.72.2.1 -r1.72.2.2
--- sbin/isakmpd/ipsec.c	13 Jun 2003 03:50:53 -0000	1.72.2.1
+++ sbin/isakmpd/ipsec.c	16 Jan 2004 00:00:21 -0000	1.72.2.2
@@ -1017,43 +1017,6 @@ ipsec_delete_spi_list (struct sockaddr *
     }
 }
 
-/*
- * deal with a NOTIFY of INVALID_SPI
- */
-static void
-ipsec_invalid_spi (struct message *msg, struct payload *p)
-{
-  struct sockaddr *dst;
-  int invspisz, off;
-  u_int32_t spi;
-  u_int16_t totsiz;
-  u_int8_t spisz;
-
-  /*
-   * get the invalid spi out of the variable sized notification data
-   * field, which is after the variable sized SPI field [which specifies
-   * the receiving entity's phase-1 SPI, not the invalid spi]
-   */
-  totsiz = GET_ISAKMP_GEN_LENGTH (p->p);
-  spisz = GET_ISAKMP_NOTIFY_SPI_SZ (p->p);
-  off = ISAKMP_NOTIFY_SPI_OFF + spisz;
-  invspisz = totsiz - off;
-
-  if (invspisz != sizeof spi)
-    {
-      LOG_DBG ((LOG_SA, 40,
-	       "ipsec_invalid_spi: SPI size %d in INVALID_SPI "
-	       "payload unsupported", spisz));
-       return;
-    }
-  memcpy (&spi, p->p + off, sizeof spi);
-
-  msg->transport->vtbl->get_dst (msg->transport, &dst);
-
-  /* delete matching SPI's from this peer */
-  ipsec_delete_spi_list (dst, 0, (u_int8_t *)&spi, 1, "INVALID_SPI");
-}
-
 static int
 ipsec_responder (struct message *msg)
 {
@@ -1103,9 +1066,6 @@ ipsec_responder (struct message *msg)
 		    "ipsec_responder: got NOTIFY of type %s",
 		    constant_lookup (isakmp_notify_cst, type)));
 
-          if (type == ISAKMP_NOTIFY_INVALID_SPI)
-              ipsec_invalid_spi (msg, p);
-
 	  p->flags |= PL_MARK;
 	}
 
@@ -1658,6 +1618,31 @@ ipsec_handle_leftover_payload (struct me
       switch (GET_ISAKMP_NOTIFY_MSG_TYPE (payload->p))
 	{
 	case IPSEC_NOTIFY_INITIAL_CONTACT:
+	  /*
+	   * Permit INITIAL-CONTACT if
+	   *   - this is not an AGGRESSIVE mode exchange
+	   *   - it is protected by an ISAKMP SA
+	   *
+	   * XXX Instead of the first condition above, we could permit this
+	   * XXX only for phase 2. In the last packet of main-mode, this
+	   * XXX payload, while encrypted, is not part of the hash digest.
+	   * XXX As we currently send our own INITIAL-CONTACTs at this point,
+	   * XXX this too would need to be changed.
+	   */
+	  if (msg->exchange->type == ISAKMP_EXCH_AGGRESSIVE)
+	    {	
+	      log_print ("ipsec_handle_leftover_payload: got INITIAL-CONTACT "
+			 "in AGGRESSIVE mode");
+	      return -1;
+	    }
+
+	  if ((msg->exchange->flags & EXCHANGE_FLAG_ENCRYPT) == 0)
+	    {
+	      log_print ("ipsec_handle_leftover_payload: got INITIAL-CONTACT "
+			 "without ISAKMP SA");
+	      return -1;
+	    }
+
 	  /*
 	   * Find out who is sending this and then delete every SA that is
 	   * ready.  Exchanges will timeout themselves and then the
Index: sbin/isakmpd/message.c
===================================================================
RCS file: /cvs/src/sbin/isakmpd/message.c,v
retrieving revision 1.57
retrieving revision 1.57.4.1
diff -u -p -r1.57 -r1.57.4.1
--- sbin/isakmpd/message.c	11 Sep 2002 09:50:44 -0000	1.57
+++ sbin/isakmpd/message.c	16 Jan 2004 00:00:21 -0000	1.57.4.1
@@ -52,10 +52,13 @@
 #include "doi.h"
 #include "exchange.h"
 #include "field.h"
+#include "hash.h"
+#include "ipsec.h"
 #include "ipsec_num.h"
 #include "isakmp.h"
 #include "log.h"
 #include "message.h"
+#include "prf.h"
 #include "sa.h"
 #include "timer.h"
 #include "transport.h"
@@ -444,6 +447,12 @@ message_validate_delete (struct message 
 {
   u_int8_t proto = GET_ISAKMP_DELETE_PROTO (p->p);
   struct doi *doi;
+  struct sa *sa, *isakmp_sa;
+  struct sockaddr *dst, *dst_isa;
+  u_int32_t nspis = GET_ISAKMP_DELETE_NSPIS (p->p);
+  u_int8_t *spis = (u_int8_t *)p->p + ISAKMP_DELETE_SPI_OFF;
+  int i;
+  char *addr;
 
   doi = doi_lookup (GET_ISAKMP_DELETE_DOI (p->p));
   if (!doi)
@@ -477,16 +486,141 @@ message_validate_delete (struct message 
     }
 
   /* Validate the SPIs.  */
+  for (i = 0; i < nspis; i++)
+    {
+      /* Get ISAKMP SA protecting this message. */
+      isakmp_sa = msg->isakmp_sa;
+      if (!isakmp_sa)
+        {
+          /* XXX should not happen? */
+          log_print ("message_validate_delete: invalid spi "
+                     "(no valid ISAKMP SA found)");
+          message_free (msg);
+          return -1;
+        }
+      isakmp_sa->transport->vtbl->get_dst (isakmp_sa->transport, &dst_isa);
+
+      /* Get SA to be deleted. */
+      msg->transport->vtbl->get_dst (msg->transport, &dst);
+      if (proto == ISAKMP_PROTO_ISAKMP)
+	sa = sa_lookup_isakmp_sa (dst, spis + i * ISAKMP_HDR_COOKIES_LEN);
+      else
+	sa = ipsec_sa_lookup (dst, ((u_int32_t *)spis)[i], proto);
+      if (!sa)
+        {
+          log_print ("message_validate_delete: invalid spi "
+		     "(no valid SA found)");
+          message_free (msg);
+          return -1;
+        }
+      sa->transport->vtbl->get_dst (sa->transport, &dst);
+
+      /* Destination addresses must match. */
+      if (dst->sa_family != dst_isa->sa_family ||
+          memcmp (sockaddr_addrdata (dst_isa), sockaddr_addrdata (dst),
+                  sockaddr_addrlen (dst)))
+        {
+          sockaddr2text (dst_isa, &addr, 0);
+
+          log_print ("message_validate_delete: invalid spi "
+                     "(illegal delete request from %s)", addr);
+          free (addr);
+          message_free (msg);
+          return -1;
+        }
+    }
 
   return 0;
 }
 
 /*
- * Validate the hash payload P in message MSG.  */
+ * Validate the hash payload P in message MSG.
+ * XXX Currently hash payloads are processed by the particular exchanges,
+ * except INFORMATIONAL.  This should be actually done here.
+ */
 static int
 message_validate_hash (struct message *msg, struct payload *p)
 {
-  /* XXX Not implemented yet.  */
+  struct sa *isakmp_sa = msg->isakmp_sa;
+  struct ipsec_sa *isa;
+  struct hash *hash;
+  struct payload *hashp = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_HASH]);
+  struct prf *prf;
+  u_int8_t *comp_hash, *rest;
+  u_int8_t message_id[ISAKMP_HDR_MESSAGE_ID_LEN];
+  size_t rest_len;
+
+  if (msg->exchange)	/* active exchange validates hash payload. */
+    return 0;
+
+  if (isakmp_sa == NULL)
+    {
+       log_print ("message_validate_hash: invalid hash information");
+       return -1;
+    }
+
+  isa = isakmp_sa->data;
+  hash = hash_get (isa->hash);
+
+  if (hash == NULL)
+    {
+       log_print ("message_validate_hash: invalid hash information");
+       return -1;
+    }
+
+  /* If no SKEYID_a, we can not do anything (should not happen).  */
+  if (!isa->skeyid_a)
+    {
+      log_print ("message_validate_hash: invalid hash information");
+      return -1;
+    }
+
+  /* Allocate the prf and start calculating our HASH(1). */
+  LOG_DBG_BUF ((LOG_MISC, 90, "message_validate_hash: SKEYID_a", isa->skeyid_a,
+		isa->skeyid_len));
+  prf = prf_alloc (isa->prf_type, hash->type, isa->skeyid_a, isa->skeyid_len);
+  if (!prf)
+    return -1;
+
+  comp_hash = (u_int8_t *)malloc (hash->hashsize);
+  if (!comp_hash)
+    {
+      log_error ("message_validate_hash: malloc (%lu) failed",
+	        (unsigned long)hash->hashsize);
+      prf_free (prf);
+      return -1;
+    }
+
+  /* This is not an active exchange. */
+  GET_ISAKMP_HDR_MESSAGE_ID (msg->iov[0].iov_base, message_id);
+
+  prf->Init (prf->prfctx);
+  LOG_DBG_BUF ((LOG_MISC, 90, "message_validate_hash: message_id",
+		message_id, ISAKMP_HDR_MESSAGE_ID_LEN));
+  prf->Update (prf->prfctx, message_id, ISAKMP_HDR_MESSAGE_ID_LEN);
+  rest = hashp->p + GET_ISAKMP_GEN_LENGTH (hashp->p);
+  rest_len = (GET_ISAKMP_HDR_LENGTH (msg->iov[0].iov_base)
+	        - (rest - (u_int8_t*)msg->iov[0].iov_base));
+  LOG_DBG_BUF ((LOG_MISC, 90, "message_validate_hash: payloads after HASH(1)",
+		rest, rest_len));
+  prf->Update (prf->prfctx, rest, rest_len);
+  prf->Final (comp_hash, prf->prfctx);
+  prf_free (prf);
+
+  if (memcmp (hashp->p + ISAKMP_HASH_DATA_OFF, comp_hash, hash->hashsize))
+    {
+      log_print ("message_validate_hash: invalid hash value for %s payload",
+		 TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_DELETE])
+		 ? "DELETE" : "NOTIFY");
+      message_drop (msg, ISAKMP_NOTIFY_INVALID_HASH_INFORMATION, 0, 1, 0);
+      free (comp_hash);
+      return -1;
+    }
+  free (comp_hash);
+
+  /* Mark the HASH as handled. */
+  hashp->flags |= PL_MARK;
+
   return 0;
 }
 
@@ -1221,6 +1355,16 @@ message_recv (struct message *msg)
   if ((msg->exchange->flags & EXCHANGE_FLAG_COMMITTED) == 0
       && (flags & ISAKMP_FLAGS_COMMIT))
     msg->exchange->flags |= EXCHANGE_FLAG_HE_COMMITTED;
+
+  /* Require encryption as soon as we have the keystate for it.  */
+  if ((flags & ISAKMP_FLAGS_ENC) == 0 &&
+      (msg->exchange->phase == 2 || msg->exchange->keystate))
+    {
+      log_print ("message_recv: cleartext phase %d message",
+                 msg->exchange->phase);
+      message_drop (msg, ISAKMP_NOTIFY_INVALID_FLAGS, 0, 1, 1);
+      return -1;
+    }
 
   /* OK let the exchange logic do the rest.  */
   exchange_run (msg);
