]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netkey/key.c
xnu-3248.60.10.tar.gz
[apple/xnu.git] / bsd / netkey / key.c
index 91b6ba0401d54d4fda30f42f8483b6e0b7a58436..7a0c50b89fee71461ec8cdccb7b1a69272d1903e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2014 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
@@ -234,6 +234,9 @@ static const int minsize[] = {
        sizeof(struct sadb_address),    /* SADB_X_EXT_ADDR_RANGE_SRC_END */
     sizeof(struct sadb_address),       /* SADB_X_EXT_ADDR_RANGE_DST_START */
        sizeof(struct sadb_address),    /* SADB_X_EXT_ADDR_RANGE_DST_END */
+       sizeof(struct sadb_address),    /* SADB_EXT_MIGRATE_ADDRESS_SRC */
+       sizeof(struct sadb_address),    /* SADB_EXT_MIGRATE_ADDRESS_DST */
+       sizeof(struct sadb_x_ipsecif),  /* SADB_X_EXT_MIGRATE_IPSECIF */
 };
 static const int maxsize[] = {
        sizeof(struct sadb_msg),        /* SADB_EXT_RESERVED */
@@ -263,6 +266,9 @@ static const int maxsize[] = {
        0,              /* SADB_X_EXT_ADDR_RANGE_SRC_END */
     0,              /* SADB_X_EXT_ADDR_RANGE_DST_START */
        0,              /* SADB_X_EXT_ADDR_RANGE_DST_END */
+       0,              /* SADB_EXT_MIGRATE_ADDRESS_SRC */
+       0,              /* SADB_EXT_MIGRATE_ADDRESS_DST */
+       sizeof(struct sadb_x_ipsecif), /* SADB_X_EXT_MIGRATE_IPSECIF */
 };
 
 static int ipsec_esp_keymin = 256;
@@ -565,6 +571,7 @@ static int key_validate_ext(const struct sadb_ext *, int);
 static int key_align(struct mbuf *, struct sadb_msghdr *);
 static struct mbuf *key_alloc_mbuf(int);
 static int key_getsastat (struct socket *, struct mbuf *, const struct sadb_msghdr *);
+static int key_migrate (struct socket *, struct mbuf *, const struct sadb_msghdr *);
 static int key_setsaval2(struct secasvar      *sav,
                                                 u_int8_t              satype,
                                                 u_int8_t              alg_auth,
@@ -581,12 +588,13 @@ static int key_setsaval2(struct secasvar      *sav,
                                                 u_int32_t             pid,
                                                 struct sadb_lifetime *lifetime_hard,
                                                 struct sadb_lifetime *lifetime_soft);
+static void bzero_keys(const struct sadb_msghdr *);
 
 extern int ipsec_bypass;
 extern int esp_udp_encap_port;
 int ipsec_send_natt_keepalive(struct secasvar *sav);
-bool ipsec_fill_offload_frame(ifnet_t ifp, struct secasvar *sav, struct ipsec_offload_frame *frame, size_t frame_data_offset);
-u_int32_t key_fill_offload_frames_for_savs (ifnet_t ifp, struct ipsec_offload_frame *frames_array, u_int32_t frames_array_count, size_t frame_data_offset);
+bool ipsec_fill_offload_frame(ifnet_t ifp, struct secasvar *sav, struct ifnet_keepalive_offload_frame *frame, size_t frame_data_offset);
+u_int32_t key_fill_offload_frames_for_savs (ifnet_t ifp, struct ifnet_keepalive_offload_frame *frames_array, u_int32_t frames_array_count, size_t frame_data_offset);
 
 void key_init(struct protosw *, struct domain *);
 
@@ -850,7 +858,7 @@ struct secasvar *key_alloc_outbound_sav_for_interface(ifnet_t interface, int fam
        
        LIST_FOREACH(sah, &sahtree, chain) {
                if (sah->ipsec_if == interface &&
-                       (family == AF_INET6 || sah->saidx.dst.ss_family == family) && /* IPv6 can go over IPv4 */
+                       (family == AF_INET6 || family == AF_INET) &&
                        sah->dir == IPSEC_DIR_OUTBOUND) {
                        /* This SAH is linked to the IPSec interface, and the right family. We found it! */
                        if (key_preferred_oldsa) {
@@ -2251,13 +2259,13 @@ key_spdadd(
     
     /* Process interfaces */
     if (ipsecifopts != NULL) {
-        if (ipsecifopts->sadb_x_ipsecif_internal_if) {
+        if (ipsecifopts->sadb_x_ipsecif_internal_if[0]) {
             ifnet_find_by_name(ipsecifopts->sadb_x_ipsecif_internal_if, &internal_if);
         }
-        if (ipsecifopts->sadb_x_ipsecif_outgoing_if) {
+        if (ipsecifopts->sadb_x_ipsecif_outgoing_if[0]) {
             outgoing_if = ipsecifopts->sadb_x_ipsecif_outgoing_if;
         }
-        if (ipsecifopts->sadb_x_ipsecif_ipsec_if) {
+        if (ipsecifopts->sadb_x_ipsecif_ipsec_if[0]) {
             ipsec_if = ipsecifopts->sadb_x_ipsecif_ipsec_if;
         }
                init_disabled = ipsecifopts->sadb_x_ipsecif_init_disabled;
@@ -2339,15 +2347,14 @@ key_spdadd(
        
 #if 1
        /*
-        * allow IPv6 over IPv4 tunnels using ESP -
+        * allow IPv6 over IPv4 or IPv4 over IPv6 tunnels using ESP -
         * otherwise reject if inner and outer address families not equal
         */
        if (newsp->req && newsp->req->saidx.src.ss_family) {
                struct sockaddr *sa;
                sa = (struct sockaddr *)(src0 + 1);
                if (sa->sa_family != newsp->req->saidx.src.ss_family) {
-                       if (newsp->req->saidx.mode != IPSEC_MODE_TUNNEL || newsp->req->saidx.proto != IPPROTO_ESP
-                           || sa->sa_family != AF_INET6 || newsp->req->saidx.src.ss_family != AF_INET) {
+                       if (newsp->req->saidx.mode != IPSEC_MODE_TUNNEL || newsp->req->saidx.proto != IPPROTO_ESP) {
                                keydb_delsecpolicy(newsp);
                 if (internal_if) {
                     ifnet_release(internal_if);
@@ -2361,8 +2368,7 @@ key_spdadd(
                struct sockaddr *sa;
                sa = (struct sockaddr *)(dst0 + 1);
                if (sa->sa_family != newsp->req->saidx.dst.ss_family) {
-                       if (newsp->req->saidx.mode != IPSEC_MODE_TUNNEL || newsp->req->saidx.proto != IPPROTO_ESP
-                           || sa->sa_family != AF_INET6 || newsp->req->saidx.dst.ss_family != AF_INET) {
+                       if (newsp->req->saidx.mode != IPSEC_MODE_TUNNEL || newsp->req->saidx.proto != IPPROTO_ESP) {
                                keydb_delsecpolicy(newsp);
                 if (internal_if) {
                     ifnet_release(internal_if);
@@ -2596,7 +2602,7 @@ key_spddelete(
     
     /* Process interfaces */
     if (ipsecifopts != NULL) {
-        if (ipsecifopts->sadb_x_ipsecif_internal_if) {
+        if (ipsecifopts->sadb_x_ipsecif_internal_if[0]) {
             ifnet_find_by_name(ipsecifopts->sadb_x_ipsecif_internal_if, &internal_if);
         }
     }
@@ -3830,6 +3836,23 @@ key_newsav2(struct secashead     *sah,
        return newsav;
 }
 
+static int
+key_migratesav(struct secasvar *sav,
+                          struct secashead *newsah)
+{
+       if (sav == NULL || newsah == NULL || sav->state != SADB_SASTATE_MATURE) {
+               return EINVAL;
+       }
+       
+       /* remove from SA header */
+       if (__LIST_CHAINED(sav))
+               LIST_REMOVE(sav, chain);
+       
+       sav->sah = newsah;
+       LIST_INSERT_TAIL(&newsah->savtree[SADB_SASTATE_MATURE], sav, secasvar, chain);
+       return 0;
+}
+
 /*
  * free() SA variable entry.
  */
@@ -4090,6 +4113,7 @@ key_setsaval(
                        }
                        sav->remote_ike_port = ((const struct sadb_sa_2*)(sa0))->sadb_sa_natt_port;
                        sav->natt_interval = ((const struct sadb_sa_2*)(sa0))->sadb_sa_natt_interval;
+                       sav->natt_offload_interval = ((const struct sadb_sa_2*)(sa0))->sadb_sa_natt_offload_interval;
                }
                
                /*
@@ -4856,7 +4880,7 @@ key_setdumpsa(
                if ((!m && !p) || (m && p))
                        goto fail;
                if (p && tres) {
-                       M_PREPEND(tres, l, M_WAITOK);
+                       M_PREPEND(tres, l, M_WAITOK, 1);
                        if (!tres)
                                goto fail;
                        bcopy(p, mtod(tres, caddr_t), l);
@@ -6364,14 +6388,14 @@ key_proto2satype(
 }
 
 static ifnet_t
-key_get_ipsec_if_from_message (const struct sadb_msghdr *mhp)
+key_get_ipsec_if_from_message (const struct sadb_msghdr *mhp, int message_type)
 {
        struct sadb_x_ipsecif *ipsecifopts = NULL;
        ifnet_t ipsec_if = NULL;
        
-       ipsecifopts = (struct sadb_x_ipsecif *)(void *)mhp->ext[SADB_X_EXT_IPSECIF];
+       ipsecifopts = (struct sadb_x_ipsecif *)(void *)mhp->ext[message_type];
        if (ipsecifopts != NULL) {
-               if (ipsecifopts->sadb_x_ipsecif_internal_if) {
+               if (ipsecifopts->sadb_x_ipsecif_ipsec_if[0]) {
                        ifnet_find_by_name(ipsecifopts->sadb_x_ipsecif_ipsec_if, &ipsec_if);
                }
        }
@@ -6380,14 +6404,14 @@ key_get_ipsec_if_from_message (const struct sadb_msghdr *mhp)
 }
 
 static u_int
-key_get_outgoing_ifindex_from_message (const struct sadb_msghdr *mhp)
+key_get_outgoing_ifindex_from_message (const struct sadb_msghdr *mhp, int message_type)
 {
        struct sadb_x_ipsecif *ipsecifopts = NULL;
        ifnet_t outgoing_if = NULL;
        
-       ipsecifopts = (struct sadb_x_ipsecif *)(void *)mhp->ext[SADB_X_EXT_IPSECIF];
+       ipsecifopts = (struct sadb_x_ipsecif *)(void *)mhp->ext[message_type];
        if (ipsecifopts != NULL) {
-               if (ipsecifopts->sadb_x_ipsecif_outgoing_if) {
+               if (ipsecifopts->sadb_x_ipsecif_outgoing_if[0]) {
                        ifnet_find_by_name(ipsecifopts->sadb_x_ipsecif_outgoing_if, &outgoing_if);
         }
     }
@@ -6454,7 +6478,7 @@ key_getspi(
        src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
        dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
        
-       ipsec_if = key_get_ipsec_if_from_message(mhp);
+       ipsec_if = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
        
        /* map satype to proto */
        if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
@@ -6512,7 +6536,7 @@ key_getspi(
        /* get a SA index */
        if ((newsah = key_getsah(&saidx)) == NULL) {
                /* create a new SA index: key_addspi is always used for inbound spi */
-               if ((newsah = key_newsah(&saidx, ipsec_if, key_get_outgoing_ifindex_from_message(mhp), IPSEC_DIR_INBOUND)) == NULL) {
+               if ((newsah = key_newsah(&saidx, ipsec_if, key_get_outgoing_ifindex_from_message(mhp, SADB_X_EXT_IPSECIF), IPSEC_DIR_INBOUND)) == NULL) {
                        lck_mtx_unlock(sadb_mutex);
                        ipseclog((LOG_DEBUG, "key_getspi: No more memory.\n"));
                        return key_senderror(so, m, ENOBUFS);
@@ -6829,7 +6853,7 @@ key_update(
        sa0 = (struct sadb_sa *)(void *)mhp->ext[SADB_EXT_SA];
        src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
        dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
-       ipsec_if = key_get_ipsec_if_from_message(mhp);
+       ipsec_if = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
        
        /* XXX boundary check against sa_len */
        KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, ipsec_if ? ipsec_if->if_index : 0, &saidx);
@@ -6943,6 +6967,152 @@ key_update(
     }
 }
 
+static int
+key_migrate(struct socket *so,
+                       struct mbuf *m,
+                       const struct sadb_msghdr *mhp)
+{
+       struct sadb_sa *sa0 = NULL;
+       struct sadb_address *src0 = NULL;
+       struct sadb_address *dst0 = NULL;
+       struct sadb_address *src1 = NULL;
+       struct sadb_address *dst1 = NULL;
+       ifnet_t ipsec_if0 = NULL;
+       ifnet_t ipsec_if1 = NULL;
+       struct secasindex saidx0;
+       struct secasindex saidx1;
+       struct secashead *sah = NULL;
+       struct secashead *newsah = NULL;
+       struct secasvar *sav = NULL;
+       u_int16_t proto;
+       
+       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       
+       /* sanity check */
+       if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
+               panic("key_migrate: NULL pointer is passed.\n");
+       
+       /* map satype to proto */
+       if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
+               ipseclog((LOG_DEBUG, "key_migrate: invalid satype is passed.\n"));
+               return key_senderror(so, m, EINVAL);
+       }
+       
+       if (mhp->ext[SADB_EXT_SA] == NULL ||
+               mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL ||
+               mhp->ext[SADB_EXT_ADDRESS_DST] == NULL ||
+               mhp->ext[SADB_EXT_MIGRATE_ADDRESS_SRC] == NULL ||
+               mhp->ext[SADB_EXT_MIGRATE_ADDRESS_DST] == NULL) {
+               ipseclog((LOG_DEBUG, "key_migrate: invalid message is passed.\n"));
+               return key_senderror(so, m, EINVAL);
+       }
+       
+       if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) ||
+               mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) ||
+               mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address) ||
+               mhp->extlen[SADB_EXT_MIGRATE_ADDRESS_SRC] < sizeof(struct sadb_address) ||
+               mhp->extlen[SADB_EXT_MIGRATE_ADDRESS_DST] < sizeof(struct sadb_address)) {
+               ipseclog((LOG_DEBUG, "key_migrate: invalid message is passed.\n"));
+               return key_senderror(so, m, EINVAL);
+       }
+       
+       lck_mtx_lock(sadb_mutex);
+       
+       sa0 = (struct sadb_sa *)(void *)mhp->ext[SADB_EXT_SA];
+       src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
+       dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
+       src1 = (struct sadb_address *)(mhp->ext[SADB_EXT_MIGRATE_ADDRESS_SRC]);
+       dst1 = (struct sadb_address *)(mhp->ext[SADB_EXT_MIGRATE_ADDRESS_DST]);
+       ipsec_if0 = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
+       ipsec_if1 = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_MIGRATE_IPSECIF);
+       
+       /* Find existing SAH and SAV */
+       KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, ipsec_if0 ? ipsec_if0->if_index : 0, &saidx0);
+       
+       LIST_FOREACH(sah, &sahtree, chain) {
+               if (sah->state != SADB_SASTATE_MATURE)
+                       continue;
+               if (key_cmpsaidx(&sah->saidx, &saidx0, CMP_HEAD) == 0)
+                       continue;
+               
+               sav = key_getsavbyspi(sah, sa0->sadb_sa_spi);
+               if (sav && sav->state == SADB_SASTATE_MATURE)
+                       break;
+       }
+       if (sah == NULL) {
+               lck_mtx_unlock(sadb_mutex);
+               ipseclog((LOG_DEBUG, "key_migrate: no mature SAH found.\n"));
+               return key_senderror(so, m, ENOENT);
+       }
+       
+       if (sav == NULL) {
+               lck_mtx_unlock(sadb_mutex);
+               ipseclog((LOG_DEBUG, "key_migrate: no SA found.\n"));
+               return key_senderror(so, m, ENOENT);
+       }
+       
+       /* Find or create new SAH */
+       KEY_SETSECASIDX(proto, sah->saidx.mode, sah->saidx.reqid, src1 + 1, dst1 + 1, ipsec_if1 ? ipsec_if1->if_index : 0, &saidx1);
+       
+       if ((newsah = key_getsah(&saidx1)) == NULL) {
+               if ((newsah = key_newsah(&saidx1, ipsec_if1, key_get_outgoing_ifindex_from_message(mhp, SADB_X_EXT_MIGRATE_IPSECIF), sah->dir)) == NULL) {
+                       lck_mtx_unlock(sadb_mutex);
+                       ipseclog((LOG_DEBUG, "key_migrate: No more memory.\n"));
+                       return key_senderror(so, m, ENOBUFS);
+               }
+       }
+       
+       /* Migrate SAV in to new SAH */
+       if (key_migratesav(sav, newsah) != 0) {
+               lck_mtx_unlock(sadb_mutex);
+               ipseclog((LOG_DEBUG, "key_migrate: Failed to migrate SA to new SAH.\n"));
+               return key_senderror(so, m, EINVAL);
+       }
+       
+       /* Reset NAT values */
+       sav->flags = sa0->sadb_sa_flags;
+       sav->remote_ike_port = ((const struct sadb_sa_2*)(sa0))->sadb_sa_natt_port;
+       sav->natt_interval = ((const struct sadb_sa_2*)(sa0))->sadb_sa_natt_interval;
+       sav->natt_offload_interval = ((const struct sadb_sa_2*)(sa0))->sadb_sa_natt_offload_interval;
+       sav->natt_last_activity = natt_now;
+       
+       /*
+        * Verify if SADB_X_EXT_NATT_MULTIPLEUSERS flag is set that
+        * SADB_X_EXT_NATT is set and SADB_X_EXT_NATT_KEEPALIVE is not
+        * set (we're not behind nat) - otherwise clear it.
+        */
+       if ((sav->flags & SADB_X_EXT_NATT_MULTIPLEUSERS) != 0)
+               if ((sav->flags & SADB_X_EXT_NATT) == 0 ||
+                       (sav->flags & SADB_X_EXT_NATT_KEEPALIVE) != 0)
+                       sav->flags &= ~SADB_X_EXT_NATT_MULTIPLEUSERS;
+       
+       lck_mtx_unlock(sadb_mutex);
+       {
+               struct mbuf *n;
+               struct sadb_msg *newmsg;
+               int mbufItems[] = {SADB_EXT_RESERVED, SADB_EXT_SA,
+                       SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST, SADB_X_EXT_IPSECIF,
+                       SADB_EXT_MIGRATE_ADDRESS_SRC, SADB_EXT_MIGRATE_ADDRESS_DST, SADB_X_EXT_MIGRATE_IPSECIF};
+               
+               /* create new sadb_msg to reply. */
+               n = key_gather_mbuf(m, mhp, 1, sizeof(mbufItems)/sizeof(int), mbufItems);
+               if (!n)
+                       return key_senderror(so, m, ENOBUFS);
+               
+               if (n->m_len < sizeof(struct sadb_msg)) {
+                       n = m_pullup(n, sizeof(struct sadb_msg));
+                       if (n == NULL)
+                               return key_senderror(so, m, ENOBUFS);
+               }
+               newmsg = mtod(n, struct sadb_msg *);
+               newmsg->sadb_msg_errno = 0;
+               newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len);
+               
+               m_freem(m);
+               return key_sendup_mbuf(so, n, KEY_SENDUP_ALL);
+       }
+}
+
 /*
  * search SAD with sequence for a SA which state is SADB_SASTATE_LARVAL.
  * only called by key_update().
@@ -7023,6 +7193,7 @@ key_add(
        /* map satype to proto */
        if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) {
                ipseclog((LOG_DEBUG, "key_add: invalid satype is passed.\n"));
+               bzero_keys(mhp);
                return key_senderror(so, m, EINVAL);
        }
        
@@ -7038,6 +7209,7 @@ key_add(
            (mhp->ext[SADB_EXT_LIFETIME_HARD] == NULL &&
             mhp->ext[SADB_EXT_LIFETIME_SOFT] != NULL)) {
                        ipseclog((LOG_DEBUG, "key_add: invalid message is passed.\n"));
+                       bzero_keys(mhp);
                        return key_senderror(so, m, EINVAL);
                }
        if (mhp->extlen[SADB_EXT_SA] < sizeof(struct sadb_sa) ||
@@ -7045,6 +7217,7 @@ key_add(
            mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) {
                /* XXX need more */
                ipseclog((LOG_DEBUG, "key_add: invalid message is passed.\n"));
+               bzero_keys(mhp);
                return key_senderror(so, m, EINVAL);
        }
        if (mhp->ext[SADB_X_EXT_SA2] != NULL) {
@@ -7060,7 +7233,7 @@ key_add(
        sa0 = (struct sadb_sa *)(void *)mhp->ext[SADB_EXT_SA];
        src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
        dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
-       ipsec_if = key_get_ipsec_if_from_message(mhp);
+       ipsec_if = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
        
        /* XXX boundary check against sa_len */
        KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, ipsec_if ? ipsec_if->if_index : 0, &saidx);
@@ -7070,9 +7243,10 @@ key_add(
        /* get a SA header */
        if ((newsah = key_getsah(&saidx)) == NULL) {
                /* create a new SA header: key_addspi is always used for outbound spi */
-               if ((newsah = key_newsah(&saidx, ipsec_if, key_get_outgoing_ifindex_from_message(mhp), IPSEC_DIR_OUTBOUND)) == NULL) {
+               if ((newsah = key_newsah(&saidx, ipsec_if, key_get_outgoing_ifindex_from_message(mhp, SADB_X_EXT_IPSECIF), IPSEC_DIR_OUTBOUND)) == NULL) {
                        lck_mtx_unlock(sadb_mutex);
                        ipseclog((LOG_DEBUG, "key_add: No more memory.\n"));
+                       bzero_keys(mhp);
                        return key_senderror(so, m, ENOBUFS);
                }
        }
@@ -7082,6 +7256,7 @@ key_add(
        error = key_setident(newsah, m, mhp);
        if (error) {
                lck_mtx_unlock(sadb_mutex);
+               bzero_keys(mhp);
                return key_senderror(so, m, error);
        }
        
@@ -7090,11 +7265,13 @@ key_add(
        if (key_getsavbyspi(newsah, sa0->sadb_sa_spi)) {
                lck_mtx_unlock(sadb_mutex);
                ipseclog((LOG_DEBUG, "key_add: SA already exists.\n"));
+               bzero_keys(mhp);
                return key_senderror(so, m, EEXIST);
        }
        newsav = key_newsav(m, mhp, newsah, &error, so);
        if (newsav == NULL) {
                lck_mtx_unlock(sadb_mutex);
+               bzero_keys(mhp);
                return key_senderror(so, m, error);
        }
        
@@ -7111,6 +7288,7 @@ key_add(
        if ((error = key_mature(newsav)) != 0) {
                key_freesav(newsav, KEY_SADB_LOCKED);
                lck_mtx_unlock(sadb_mutex);
+               bzero_keys(mhp);
                return key_senderror(so, m, error);
        }
        
@@ -7128,9 +7306,13 @@ key_add(
                n = key_getmsgbuf_x1(m, mhp);
                if (n == NULL) {
                        ipseclog((LOG_DEBUG, "key_update: No more memory.\n"));
+                       bzero_keys(mhp);
                        return key_senderror(so, m, ENOBUFS);
                }
                
+               // mh.ext points to the mbuf content.
+               // Zero out Encryption and Integrity keys if present.
+               bzero_keys(mhp);
                m_freem(m);
                return key_sendup_mbuf(so, n, KEY_SENDUP_ALL);
     }
@@ -7328,7 +7510,7 @@ key_delete(
        sa0 = (struct sadb_sa *)(void *)mhp->ext[SADB_EXT_SA];
        src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
        dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
-       ipsec_if = key_get_ipsec_if_from_message(mhp);
+       ipsec_if = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
        
        /* XXX boundary check against sa_len */
        KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, ipsec_if ? ipsec_if->if_index : 0, &saidx);
@@ -7403,7 +7585,7 @@ key_delete_all(
        
        src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
        dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
-       ipsec_if = key_get_ipsec_if_from_message(mhp);
+       ipsec_if = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
        
        /* XXX boundary check against sa_len */
        KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, ipsec_if ? ipsec_if->if_index : 0, &saidx);
@@ -7519,7 +7701,7 @@ key_get(
        sa0 = (struct sadb_sa *)(void *)mhp->ext[SADB_EXT_SA];
        src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
        dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
-       ipsec_if = key_get_ipsec_if_from_message(mhp);
+       ipsec_if = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
        
        /* XXX boundary check against sa_len */
        KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, ipsec_if ? ipsec_if->if_index : 0, &saidx);
@@ -7790,7 +7972,7 @@ key_getcomb_ah(void)
                                m->m_next = NULL;
                        }
                } else
-                       M_PREPEND(m, l, M_WAITOK);
+                       M_PREPEND(m, l, M_WAITOK, 1);
                if (!m)
                        return NULL;
                
@@ -7836,7 +8018,7 @@ key_getcomb_ipcomp(void)
                                m->m_next = NULL;
                        }
                } else
-                       M_PREPEND(m, l, M_WAITOK);
+                       M_PREPEND(m, l, M_WAITOK, 1);
                if (!m)
                        return NULL;
                
@@ -7882,7 +8064,7 @@ key_getprop(
        
        if (!m)
                return NULL;
-       M_PREPEND(m, l, M_WAITOK);
+       M_PREPEND(m, l, M_WAITOK, 1);
        if (!m)
                return NULL;
        
@@ -8316,7 +8498,7 @@ key_acquire2(
        
        src0 = (const struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
        dst0 = (const struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
-       ipsec_if = key_get_ipsec_if_from_message(mhp);
+       ipsec_if = key_get_ipsec_if_from_message(mhp, SADB_X_EXT_IPSECIF);
        
        /* XXX boundary check against sa_len */
        /* cast warnings */
@@ -9014,8 +9196,69 @@ static int (*key_typesw[])(struct socket *, struct mbuf *,
        key_getsastat,   /* SADB_GETSASTAT */
        key_spdenable,   /* SADB_X_SPDENABLE */
        key_spddisable,   /* SADB_X_SPDDISABLE */
+       key_migrate,   /* SADB_MIGRATE */
 };
 
+static void
+bzero_mbuf(struct mbuf *m)
+{
+       struct mbuf *mptr  = m;
+       struct sadb_msg *msg = NULL;
+       int offset = 0;
+
+       if (!mptr) {
+               return;
+       }
+
+       if (mptr->m_len >= sizeof(struct sadb_msg)) {
+               msg = mtod(mptr, struct sadb_msg *);
+               if (msg->sadb_msg_type != SADB_ADD &&
+                   msg->sadb_msg_type != SADB_UPDATE) {
+                       return;
+               }
+               offset = sizeof(struct sadb_msg);
+       }
+       bzero(mptr->m_data+offset, mptr->m_len-offset);
+       mptr = mptr->m_next;
+       while (mptr != NULL) {
+               bzero(mptr->m_data, mptr->m_len);
+               mptr = mptr->m_next;
+       }
+}
+
+static void
+bzero_keys(const struct sadb_msghdr *mh)
+{
+       int extlen = 0;
+       int offset = 0;
+
+       if (!mh) {
+               return;
+       }
+       offset = sizeof(struct sadb_key);
+
+       if (mh->ext[SADB_EXT_KEY_ENCRYPT]) {
+               struct sadb_key *key = (struct sadb_key*)mh->ext[SADB_EXT_KEY_ENCRYPT];
+               extlen = key->sadb_key_bits >> 3;
+
+               if (mh->extlen[SADB_EXT_KEY_ENCRYPT] >= offset + extlen) {
+                       bzero((uint8_t *)mh->ext[SADB_EXT_KEY_ENCRYPT]+offset, extlen);
+               } else {
+                       bzero(mh->ext[SADB_EXT_KEY_ENCRYPT], mh->extlen[SADB_EXT_KEY_ENCRYPT]);
+               }
+       }
+       if (mh->ext[SADB_EXT_KEY_AUTH]) {
+               struct sadb_key *key = (struct sadb_key*)mh->ext[SADB_EXT_KEY_AUTH];
+               extlen = key->sadb_key_bits >> 3;
+
+               if (mh->extlen[SADB_EXT_KEY_AUTH] >= offset + extlen) {
+                       bzero((uint8_t *)mh->ext[SADB_EXT_KEY_AUTH]+offset, extlen);
+               } else {
+                       bzero(mh->ext[SADB_EXT_KEY_AUTH], mh->extlen[SADB_EXT_KEY_AUTH]);
+               }
+       }
+}
+
 /*
  * parse sadb_msg buffer to process PFKEYv2,
  * and create a data to response if needed.
@@ -9037,7 +9280,8 @@ key_parse(
        u_int orglen;
        int error;
        int target;
-       
+       Boolean keyAligned = FALSE;
+
        lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
@@ -9101,12 +9345,14 @@ key_parse(
                        }
                }
                if (!n) {
+                       bzero_mbuf(m);
                        m_freem(m);
                        return ENOBUFS;
                }
                m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t));
                n->m_pkthdr.len = n->m_len = m->m_pkthdr.len;
                n->m_next = NULL;
+               bzero_mbuf(m);
                m_freem(m);
                m = n;
        }
@@ -9117,10 +9363,12 @@ key_parse(
                return error;
        
        if (m->m_next) {        /*XXX*/
+               bzero_mbuf(m);
                m_freem(m);
                return ENOBUFS;
        }
        
+       keyAligned = TRUE;
        msg = mh.msg;
        
        /* check SA type */
@@ -9277,9 +9525,16 @@ key_parse(
                goto senderror;
        }
        
-       return (*key_typesw[msg->sadb_msg_type])(so, m, &mh);
-       
+       error = (*key_typesw[msg->sadb_msg_type])(so, m, &mh);
+
+       return error;
+
 senderror:
+       if (keyAligned) {
+               bzero_keys(&mh);
+       } else {
+               bzero_mbuf(m);
+       }
        msg->sadb_msg_errno = error;
        return key_sendup_mbuf(so, m, target);
 }
@@ -9367,6 +9622,9 @@ key_align(
                        case SADB_X_EXT_ADDR_RANGE_SRC_END:
                        case SADB_X_EXT_ADDR_RANGE_DST_START:
                        case SADB_X_EXT_ADDR_RANGE_DST_END:
+                       case SADB_EXT_MIGRATE_ADDRESS_SRC:
+                       case SADB_EXT_MIGRATE_ADDRESS_DST:
+                       case SADB_X_EXT_MIGRATE_IPSECIF:
                                /* duplicate check */
                                /*
                                 * XXX Are there duplication payloads of either
@@ -9376,6 +9634,7 @@ key_align(
                                        ipseclog((LOG_DEBUG,
                                                          "key_align: duplicate ext_type %u "
                                                          "is passed.\n", ext->sadb_ext_type));
+                                       bzero_mbuf(m);
                                        m_freem(m);
                                        PFKEY_STAT_INCREMENT(pfkeystat.out_dupext);
                                        return EINVAL;
@@ -9385,6 +9644,7 @@ key_align(
                                ipseclog((LOG_DEBUG,
                                                  "key_align: invalid ext_type %u is passed.\n",
                                                  ext->sadb_ext_type));
+                               bzero_mbuf(m);
                                m_freem(m);
                                PFKEY_STAT_INCREMENT(pfkeystat.out_invexttype);
                                return EINVAL;
@@ -9393,6 +9653,7 @@ key_align(
                extlen = PFKEY_UNUNIT64(ext->sadb_ext_len);
                
                if (key_validate_ext(ext, extlen)) {
+                       bzero_mbuf(m);
                        m_freem(m);
                        PFKEY_STAT_INCREMENT(pfkeystat.out_invlen);
                        return EINVAL;
@@ -9411,6 +9672,7 @@ key_align(
        }
        
        if (off != end) {
+               bzero_mbuf(m);
                m_freem(m);
                PFKEY_STAT_INCREMENT(pfkeystat.out_invlen);
                return EINVAL;
@@ -9450,6 +9712,8 @@ key_validate_ext(
                case SADB_X_EXT_ADDR_RANGE_SRC_END:
                case SADB_X_EXT_ADDR_RANGE_DST_START:
                case SADB_X_EXT_ADDR_RANGE_DST_END:
+               case SADB_EXT_MIGRATE_ADDRESS_SRC:
+               case SADB_EXT_MIGRATE_ADDRESS_DST:
                        baselen = PFKEY_ALIGN8(sizeof(struct sadb_address));
                        checktype = ADDR;
                        break;
@@ -10007,13 +10271,13 @@ key_delsp_for_ipsec_if (ifnet_t ipsec_if)
 
 __private_extern__ u_int32_t
 key_fill_offload_frames_for_savs (ifnet_t ifp,
-                                                                 struct ipsec_offload_frame *frames_array,
-                                                                 u_int32_t frames_array_count,
-                                                                 size_t frame_data_offset)
+    struct ifnet_keepalive_offload_frame *frames_array,
+    u_int32_t frames_array_count,
+    size_t frame_data_offset)
 {
        struct secashead *sah = NULL;
        struct secasvar *sav = NULL;
-       struct ipsec_offload_frame *frame = frames_array;
+       struct ifnet_keepalive_offload_frame *frame = frames_array;
        u_int32_t frame_index = 0;
 
        if (frame == NULL || frames_array_count == 0) {