]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netkey/key.c
xnu-4570.31.3.tar.gz
[apple/xnu.git] / bsd / netkey / key.c
index 2d91aa70b219e51a54f666f1e2208b290e160b0d..a7935a5f20202faf1c7b2e0a7093191fa08af72d 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@
  *
 #include <netkey/keysock.h>
 #include <netkey/key_debug.h>
 #include <stdarg.h>
-
+#include <libkern/crypto/rand.h>
 
 #include <netinet6/ipsec.h>
 #if INET6
@@ -172,7 +172,8 @@ static int ipsec_sav_count = 0;
 
 static u_int32_t acq_seq = 0;
 static int key_tick_init_random = 0;
-__private_extern__ u_int32_t natt_now = 0;
+static u_int64_t up_time = 0;
+__private_extern__ u_int64_t natt_now = 0;
 
 static LIST_HEAD(_sptree, secpolicy) sptree[IPSEC_DIR_MAX];    /* SPD */
 static LIST_HEAD(_sahtree, secashead) sahtree;                 /* SAD */
@@ -588,12 +589,12 @@ 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 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 *);
 
@@ -676,7 +677,7 @@ static void
 key_start_timehandler(void)
 {
        /* must be called while locked */
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        if (key_timehandler_running == 0) {
                key_timehandler_running = 1;
                (void)timeout((void *)key_timehandler, (void *)0, hz);
@@ -702,7 +703,7 @@ key_allocsp(
        struct secpolicy *sp;
        struct timeval tv;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        /* sanity check */
        if (spidx == NULL)
                panic("key_allocsp: NULL pointer is passed.\n");
@@ -851,11 +852,14 @@ struct secasvar *key_alloc_outbound_sav_for_interface(ifnet_t interface, int fam
        if (interface == NULL)
         return NULL;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        lck_mtx_lock(sadb_mutex);
        
        LIST_FOREACH(sah, &sahtree, chain) {
+               if (sah->state == SADB_SASTATE_DEAD) {
+                       continue;
+               }
                if (sah->ipsec_if == interface &&
                        (family == AF_INET6 || family == AF_INET) &&
                        sah->dir == IPSEC_DIR_OUTBOUND) {
@@ -906,7 +910,7 @@ key_checkrequest(
        int error;
        struct sockaddr_in *sin;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        *sav = NULL;
        
@@ -1100,7 +1104,7 @@ key_do_allocsa_policy(
 {
        struct secasvar *sav, *nextsav, *candidate, *natt_candidate, *no_natt_candidate, *d;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        /* initialize */
        candidate = NULL;
@@ -1229,6 +1233,17 @@ key_allocsa(
                        caddr_t dst,
                        u_int proto,
                        u_int32_t spi)
+{
+       return key_allocsa_extended(family, src, dst, proto, spi, NULL);
+}
+
+struct secasvar *
+key_allocsa_extended(u_int family,
+                                        caddr_t src,
+                                        caddr_t dst,
+                                        u_int proto,
+                                        u_int32_t spi,
+                                        ifnet_t interface)
 {
        struct secasvar *sav, *match;
        u_int stateidx, state, tmpidx, matchidx;
@@ -1237,7 +1252,7 @@ key_allocsa(
        const u_int *saorder_state_valid;
        int arraysize;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (src == NULL || dst == NULL)
@@ -1271,6 +1286,10 @@ key_allocsa(
        LIST_FOREACH(sav, &spihash[SPIHASH(spi)], spihash) {
                if (sav->spi != spi)
                        continue;
+               if (interface != NULL &&
+                       sav->sah->ipsec_if != interface) {
+                       continue;
+               }
                if (proto != sav->sah->saidx.proto)
                        continue;
                if (family != sav->sah->saidx.src.ss_family ||
@@ -1444,7 +1463,7 @@ key_do_get_translated_port(
        struct secasvar *currsav, *nextsav, *candidate;
        
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        /* initilize */
        candidate = NULL;
@@ -1514,7 +1533,7 @@ key_freesp(
        if (!locked)
                lck_mtx_lock(sadb_mutex);
        else
-               lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+               LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        sp->refcnt--;
        KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
            printf("DP freesp cause refcnt--:%d SP:0x%llx\n",
@@ -1545,7 +1564,7 @@ key_freesav(
        if (!locked)
                lck_mtx_lock(sadb_mutex);
        else
-               lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+               LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        sav->refcnt--;
        KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
            printf("DP freesav cause refcnt--:%d SA:0x%llx SPI %u\n",
@@ -1572,7 +1591,7 @@ key_delsp(
        if (sp == NULL)
                panic("key_delsp: NULL pointer is passed.\n");
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        sp->state = IPSEC_SPSTATE_DEAD;
        
        if (sp->refcnt > 0)
@@ -1624,7 +1643,7 @@ key_getsp(
 {
        struct secpolicy *sp;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        /* sanity check */
        if (spidx == NULL)
@@ -1653,7 +1672,7 @@ key_getspbyid(
 {
        struct secpolicy *sp;
        
-    lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+    LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
     
     lck_mtx_lock(sadb_mutex);
     sp = __key_getspbyid(id);
@@ -1667,7 +1686,7 @@ __key_getspbyid(u_int32_t id)
 {
        struct secpolicy *sp;
     
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
     
        LIST_FOREACH(sp, &sptree[IPSEC_DIR_INBOUND], chain) {
                if (sp->state == IPSEC_SPSTATE_DEAD)
@@ -1695,7 +1714,7 @@ key_newsp(void)
 {
        struct secpolicy *newsp = NULL;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        newsp = keydb_newsecpolicy();
        if (!newsp)
                return newsp;
@@ -1719,7 +1738,7 @@ key_msg2sp(
 {
        struct secpolicy *newsp;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (xpl0 == NULL)
@@ -1769,6 +1788,13 @@ key_msg2sp(
                        xisr = (struct sadb_x_ipsecrequest *)(xpl0 + 1);
                        
                        while (tlen > 0) {
+                               if (tlen < sizeof(*xisr)) {
+                                       ipseclog((LOG_DEBUG, "key_msg2sp: "
+                                                         "invalid ipsecrequest.\n"));
+                                       key_freesp(newsp, KEY_SADB_UNLOCKED);
+                                       *error = EINVAL;
+                                       return NULL;
+                               }
                                
                                /* length check */
                                if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr)) {
@@ -1872,8 +1898,25 @@ key_msg2sp(
                                /* set IP addresses if there */
                                if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) {
                                        struct sockaddr *paddr;
+
+                                       if (tlen < xisr->sadb_x_ipsecrequest_len) {
+                                               ipseclog((LOG_DEBUG, "key_msg2sp: invalid request "
+                                                                 "address length.\n"));
+                                               key_freesp(newsp, KEY_SADB_UNLOCKED);
+                                               *error = EINVAL;
+                                               return NULL;
+                                       }
                                        
                                        paddr = (struct sockaddr *)(xisr + 1);
+                                       uint8_t src_len = paddr->sa_len;
+
+                                       if (xisr->sadb_x_ipsecrequest_len < src_len) {
+                                               ipseclog((LOG_DEBUG, "key_msg2sp: invalid request "
+                                                                 "invalid source address length.\n"));
+                                               key_freesp(newsp, KEY_SADB_UNLOCKED);
+                                               *error = EINVAL;
+                                               return NULL;
+                                       }
                                        
                                        /* validity check */
                                        if (paddr->sa_len
@@ -1884,11 +1927,20 @@ key_msg2sp(
                                                *error = EINVAL;
                                                return NULL;
                                        }
+
                                        bcopy(paddr, &(*p_isr)->saidx.src,
-                                                 paddr->sa_len);
+                                                 MIN(paddr->sa_len, sizeof((*p_isr)->saidx.src)));
                                        
-                                       paddr = (struct sockaddr *)((caddr_t)paddr
-                                                                                               + paddr->sa_len);
+                                       paddr = (struct sockaddr *)((caddr_t)paddr + paddr->sa_len);
+                                       uint8_t dst_len = paddr->sa_len;
+
+                                       if (xisr->sadb_x_ipsecrequest_len < (src_len + dst_len)) {
+                                               ipseclog((LOG_DEBUG, "key_msg2sp: invalid request "
+                                                                 "invalid dest address length.\n"));
+                                               key_freesp(newsp, KEY_SADB_UNLOCKED);
+                                               *error = EINVAL;
+                                               return NULL;
+                                       }
                                        
                                        /* validity check */
                                        if (paddr->sa_len
@@ -1899,8 +1951,9 @@ key_msg2sp(
                                                *error = EINVAL;
                                                return NULL;
                                        }
+
                                        bcopy(paddr, &(*p_isr)->saidx.dst,
-                                                 paddr->sa_len);
+                                                 MIN(paddr->sa_len, sizeof((*p_isr)->saidx.dst)));
                                }
                                
                                (*p_isr)->sp = newsp;
@@ -2133,7 +2186,7 @@ key_spdadd(
                   struct mbuf *m,
                   const struct sadb_msghdr *mhp)
 {
-       struct sadb_address *src0, *dst0, *src1, *dst1;
+       struct sadb_address *src0, *dst0, *src1 = NULL, *dst1 = NULL;
        struct sadb_x_policy *xpl0, *xpl;
        struct sadb_lifetime *lft = NULL;
        struct secpolicyindex spidx;
@@ -2149,7 +2202,7 @@ key_spdadd(
        int init_disabled = 0;
        int address_family, address_len;
     
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -2535,7 +2588,7 @@ key_spddelete(
                          struct mbuf *m,
                          const struct sadb_msghdr *mhp)
 {
-       struct sadb_address *src0, *dst0, *src1, *dst1;
+       struct sadb_address *src0, *dst0, *src1 = NULL, *dst1 = NULL;
        struct sadb_x_policy *xpl0;
        struct secpolicyindex spidx;
        struct secpolicy *sp;
@@ -2544,7 +2597,7 @@ key_spddelete(
     int use_src_range = 0;
     int use_dst_range = 0;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
     
        /* sanity check */
        if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -2689,7 +2742,7 @@ key_spddelete2(
        u_int32_t id;
        struct secpolicy *sp;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -2779,7 +2832,7 @@ key_spdenable(
        u_int32_t id;
        struct secpolicy *sp;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -2839,7 +2892,7 @@ key_spddisable(
        u_int32_t id;
        struct secpolicy *sp;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -2912,7 +2965,7 @@ key_spdget(
        struct secpolicy *sp;
        struct mbuf *n;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -2966,7 +3019,7 @@ key_spdacquire(
        struct secspacq *newspacq;
        int error;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (sp == NULL)
@@ -3304,7 +3357,7 @@ key_spdexpire(
        int error = EINVAL;
        struct sadb_lifetime *lt;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (sp == NULL)
@@ -3511,7 +3564,7 @@ key_delsah(
        u_int stateidx, state;
        int zombie = 0;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        /* sanity check */
        if (sah == NULL)
@@ -3597,7 +3650,7 @@ key_newsav(
        struct secasvar *newsav;
        const struct sadb_sa *xsa;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        /* sanity check */
        if (m == NULL || mhp == NULL || mhp->msg == NULL || sah == NULL)
@@ -3762,7 +3815,7 @@ key_newsav2(struct secashead     *sah,
 {
        struct secasvar *newsav;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        /* sanity check */
        if (sah == NULL)
@@ -3860,7 +3913,7 @@ key_delsav(
                   struct secasvar *sav)
 {
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        /* sanity check */
        if (sav == NULL)
@@ -3929,7 +3982,7 @@ key_getsah(struct secasindex *saidx)
 {
        struct secashead *sah;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        LIST_FOREACH(sah, &sahtree, chain) {
                if (sah->state == SADB_SASTATE_DEAD)
@@ -3947,7 +4000,7 @@ key_newsah2 (struct secasindex *saidx,
 {
        struct secashead *sah;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        sah = key_getsah(saidx);
        if (!sah) {
@@ -3971,7 +4024,7 @@ key_checkspidup(
        struct secasvar *sav;
        u_int stateidx, state;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        /* check address family */
        if (saidx->src.ss_family != saidx->dst.ss_family) {
@@ -4001,7 +4054,7 @@ key_setspi(
                   struct secasvar *sav,
                   u_int32_t spi)
 {
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        sav->spi = spi;
        if (sav->spihash.le_prev || sav->spihash.le_next)
                LIST_REMOVE(sav, spihash);
@@ -4023,7 +4076,7 @@ key_getsavbyspi(
        struct secasvar *sav, *match;
        u_int stateidx, state, matchidx;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        match = NULL;
        matchidx = _ARRAYLEN(saorder_state_alive);
        LIST_FOREACH(sav, &spihash[SPIHASH(spi)], spihash) {
@@ -4064,7 +4117,7 @@ key_setsaval(
        int error = 0;
        struct timeval tv;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        /* sanity check */
        if (m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -4244,7 +4297,11 @@ key_setsaval(
                        }
                        
                        /* initialize */
-                       key_randomfill(sav->iv, sav->ivlen);
+                       if (sav->alg_enc == SADB_X_EALG_AES_GCM) {
+                               bzero(sav->iv, sav->ivlen);
+                       } else {
+                               key_randomfill(sav->iv, sav->ivlen);
+                       }
 #endif
                        break;
                case SADB_SATYPE_AH:
@@ -4401,7 +4458,7 @@ key_setsaval2(struct secasvar      *sav,
        int error = 0;
        struct timeval tv;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        /* initialization */
        sav->replay = NULL;
@@ -4494,7 +4551,11 @@ key_setsaval2(struct secasvar      *sav,
                                }
                        }
                        /* initialize */
-                       key_randomfill(sav->iv, sav->ivlen);
+                       if (sav->alg_enc == SADB_X_EALG_AES_GCM) {
+                               bzero(sav->iv, sav->ivlen);
+                       } else {
+                               key_randomfill(sav->iv, sav->ivlen);
+                       }
                }
 #endif
        }
@@ -4602,7 +4663,7 @@ key_mature(
        
        mature = 0;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        /* check SPI value */
        switch (sav->sah->saidx.proto) {
@@ -5287,7 +5348,7 @@ key_newbuf(
 {
        caddr_t new;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        KMALLOC_NOWAIT(new, caddr_t, len);
        if (new == NULL) {
                lck_mtx_unlock(sadb_mutex);
@@ -6213,8 +6274,10 @@ key_timehandler(void)
                key_tick_init_random = 0;
                key_srandom();
        }
-       
-       natt_now++;
+
+       uint64_t acc_sleep_time = 0;
+       absolutetime_to_nanoseconds(mach_absolutetime_asleep, &acc_sleep_time);
+       natt_now = ++up_time + (acc_sleep_time / NSEC_PER_SEC);
        
        lck_mtx_unlock(sadb_mutex);
        
@@ -6312,8 +6375,7 @@ key_randomfill(
                           size_t l)
 {
 #ifdef __APPLE__
-       
-       read_random(p, (u_int)l);
+       cc_rand_generate(p, l); 
 #else
        size_t n;
        u_int32_t v;
@@ -6356,7 +6418,6 @@ key_satype2proto(
                        return IPPROTO_ESP;
                case SADB_X_SATYPE_IPCOMP:
                        return IPPROTO_IPCOMP;
-                       break;
                default:
                        return 0;
        }
@@ -6379,7 +6440,6 @@ key_proto2satype(
                        return SADB_SATYPE_ESP;
                case IPPROTO_IPCOMP:
                        return SADB_X_SATYPE_IPCOMP;
-                       break;
                default:
                        return 0;
        }
@@ -6448,7 +6508,7 @@ key_getspi(
        u_int32_t reqid;
        int error;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -6650,7 +6710,7 @@ key_getspi2(struct sockaddr      *src,
        u_int32_t         spi;
        struct secasindex saidx;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* XXX boundary check against sa_len */
        KEY_SETSECASIDX(proto, mode, reqid, src, dst, 0, &saidx);
@@ -6711,7 +6771,7 @@ key_do_getnewspi(
        u_int32_t keymin, keymax;
        int count = key_spi_trycnt;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        /* set spi range to allocate */
        if (spirange != NULL) {
@@ -6804,7 +6864,7 @@ key_update(
        u_int16_t flags2;
        int error;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -6985,7 +7045,7 @@ key_migrate(struct socket *so,
        struct secasvar *sav = NULL;
        u_int16_t proto;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -7074,7 +7134,7 @@ key_migrate(struct socket *so,
        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
@@ -7128,7 +7188,7 @@ key_getsavbyseq(
        struct secasvar *sav;
        u_int state;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        state = SADB_SASTATE_LARVAL;
        
@@ -7183,7 +7243,7 @@ key_add(
        u_int32_t reqid;
        int error;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -7192,6 +7252,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);
        }
        
@@ -7207,6 +7268,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) ||
@@ -7214,6 +7276,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) {
@@ -7242,6 +7305,7 @@ key_add(
                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);
                }
        }
@@ -7251,6 +7315,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);
        }
        
@@ -7259,11 +7324,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);
        }
        
@@ -7280,6 +7347,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);
        }
        
@@ -7297,9 +7365,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);
     }
@@ -7315,7 +7387,7 @@ key_setident(
        const struct sadb_ident *idsrc, *iddst;
        int idsrclen, iddstlen;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        /* sanity check */
        if (sah == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -7453,7 +7525,7 @@ key_delete(
        struct secasvar *sav = NULL;
        u_int16_t proto;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -7568,7 +7640,7 @@ key_delete_all(
        struct secasvar *sav, *nextsav;
        u_int stateidx, state;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]);
        dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]);
@@ -7660,7 +7732,7 @@ key_get(
        struct secasvar *sav = NULL;
        u_int16_t proto;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -8101,7 +8173,7 @@ key_acquire(
        int error = -1;
        u_int32_t seq;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (saidx == NULL)
@@ -8310,7 +8382,7 @@ key_getacq(
 {
        struct secacq *acq;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        LIST_FOREACH(acq, &acqtree, chain) {
                if (key_cmpsaidx(saidx, &acq->saidx, CMP_EXACTLY))
@@ -8326,7 +8398,7 @@ key_getacqbyseq(
 {
        struct secacq *acq;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        LIST_FOREACH(acq, &acqtree, chain) {
                if (acq->seq == seq)
@@ -8372,7 +8444,7 @@ key_getspacq(
 {
        struct secspacq *acq;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        LIST_FOREACH(acq, &spacqtree, chain) {
                if (key_cmpspidx_exactly(spidx, &acq->spidx))
@@ -8776,7 +8848,7 @@ key_expire(
        int error = -1;
        struct sadb_lifetime *lt;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (sav == NULL)
@@ -9000,7 +9072,7 @@ key_dump(
        struct mbuf *n;
        int error = 0;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -9214,7 +9286,7 @@ bzero_mbuf(struct mbuf *m)
 }
 
 static void
-bzero_keys(struct sadb_msghdr *mh)
+bzero_keys(const struct sadb_msghdr *mh)
 {
        int extlen = 0;
        int offset = 0;
@@ -9246,6 +9318,82 @@ bzero_keys(struct sadb_msghdr *mh)
        }
 }
 
+static int
+key_validate_address_pair(struct sadb_address *src0,
+                                                 struct sadb_address *dst0)
+{
+       u_int plen = 0;
+
+       /* check upper layer protocol */
+       if (src0->sadb_address_proto != dst0->sadb_address_proto) {
+               ipseclog((LOG_DEBUG, "key_parse: upper layer protocol mismatched.\n"));
+               PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
+               return (EINVAL);
+       }
+
+       /* check family */
+       if (PFKEY_ADDR_SADDR(src0)->sa_family !=
+               PFKEY_ADDR_SADDR(dst0)->sa_family) {
+               ipseclog((LOG_DEBUG, "key_parse: address family mismatched.\n"));
+               PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
+               return (EINVAL);
+       }
+       if (PFKEY_ADDR_SADDR(src0)->sa_len !=
+               PFKEY_ADDR_SADDR(dst0)->sa_len) {
+               ipseclog((LOG_DEBUG,
+                                 "key_parse: address struct size mismatched.\n"));
+               PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
+               return (EINVAL);
+       }
+
+       switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
+               case AF_INET:
+                       if (PFKEY_ADDR_SADDR(src0)->sa_len != sizeof(struct sockaddr_in)) {
+                               PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
+                               return (EINVAL);
+                       }
+                       break;
+               case AF_INET6:
+                       if (PFKEY_ADDR_SADDR(src0)->sa_len != sizeof(struct sockaddr_in6)) {
+                               PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
+                               return (EINVAL);
+                       }
+                       break;
+               default:
+                       ipseclog((LOG_DEBUG,
+                                         "key_parse: unsupported address family.\n"));
+                       PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
+                       return (EAFNOSUPPORT);
+       }
+
+       switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
+               case AF_INET:
+                       plen = sizeof(struct in_addr) << 3;
+                       break;
+               case AF_INET6:
+                       plen = sizeof(struct in6_addr) << 3;
+                       break;
+               default:
+                       plen = 0;       /*fool gcc*/
+                       break;
+       }
+
+       /* check max prefix length */
+       if (src0->sadb_address_prefixlen > plen ||
+               dst0->sadb_address_prefixlen > plen) {
+               ipseclog((LOG_DEBUG,
+                                 "key_parse: illegal prefixlen.\n"));
+               PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
+               return (EINVAL);
+       }
+
+       /*
+        * prefixlen == 0 is valid because there can be a case when
+        * all addresses are matched.
+        */
+       return (0);
+}
+
 /*
  * parse sadb_msg buffer to process PFKEYv2,
  * and create a data to response if needed.
@@ -9269,7 +9417,7 @@ key_parse(
        int target;
        Boolean keyAligned = FALSE;
 
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        /* sanity check */
        if (m == NULL || so == NULL)
@@ -9418,91 +9566,41 @@ key_parse(
                        goto senderror;
        }
        
-       /* check field of upper layer protocol and address family */
-       if (mh.ext[SADB_EXT_ADDRESS_SRC] != NULL
-               && mh.ext[SADB_EXT_ADDRESS_DST] != NULL) {
-               struct sadb_address *src0, *dst0;
-               u_int plen;
-               
-               src0 = (struct sadb_address *)(mh.ext[SADB_EXT_ADDRESS_SRC]);
-               dst0 = (struct sadb_address *)(mh.ext[SADB_EXT_ADDRESS_DST]);
-               
-               /* check upper layer protocol */
-               if (src0->sadb_address_proto != dst0->sadb_address_proto) {
-                       ipseclog((LOG_DEBUG, "key_parse: upper layer protocol mismatched.\n"));
-                       PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
-                       error = EINVAL;
+       /* Validate address fields for matching families, lengths, etc. */
+       void *src0 = mh.ext[SADB_EXT_ADDRESS_SRC];
+       void *dst0 = mh.ext[SADB_EXT_ADDRESS_DST];
+       if (mh.ext[SADB_X_EXT_ADDR_RANGE_SRC_START] != NULL &&
+               mh.ext[SADB_X_EXT_ADDR_RANGE_SRC_END] != NULL) {
+
+               error = key_validate_address_pair((struct sadb_address *)(mh.ext[SADB_X_EXT_ADDR_RANGE_SRC_START]),
+                                                                                 (struct sadb_address *)(mh.ext[SADB_X_EXT_ADDR_RANGE_SRC_END]));
+               if (error != 0) {
                        goto senderror;
                }
-               
-               /* check family */
-               if (PFKEY_ADDR_SADDR(src0)->sa_family !=
-                   PFKEY_ADDR_SADDR(dst0)->sa_family) {
-                       ipseclog((LOG_DEBUG, "key_parse: address family mismatched.\n"));
-                       PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
-                       error = EINVAL;
-                       goto senderror;
+
+               if (src0 == NULL) {
+                       src0 = mh.ext[SADB_X_EXT_ADDR_RANGE_SRC_START];
                }
-               if (PFKEY_ADDR_SADDR(src0)->sa_len !=
-                   PFKEY_ADDR_SADDR(dst0)->sa_len) {
-                       ipseclog((LOG_DEBUG,
-                                         "key_parse: address struct size mismatched.\n"));
-                       PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
-                       error = EINVAL;
+       }
+       if (mh.ext[SADB_X_EXT_ADDR_RANGE_DST_START] != NULL &&
+               mh.ext[SADB_X_EXT_ADDR_RANGE_DST_END] != NULL) {
+
+               error = key_validate_address_pair((struct sadb_address *)(mh.ext[SADB_X_EXT_ADDR_RANGE_DST_START]),
+                                                                                 (struct sadb_address *)(mh.ext[SADB_X_EXT_ADDR_RANGE_DST_END]));
+               if (error != 0) {
                        goto senderror;
                }
-               
-               switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
-                       case AF_INET:
-                               if (PFKEY_ADDR_SADDR(src0)->sa_len !=
-                                       sizeof(struct sockaddr_in)) {
-                                       PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
-                                       error = EINVAL;
-                                       goto senderror;
-                               }
-                               break;
-                       case AF_INET6:
-                               if (PFKEY_ADDR_SADDR(src0)->sa_len !=
-                                       sizeof(struct sockaddr_in6)) {
-                                       PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
-                                       error = EINVAL;
-                                       goto senderror;
-                               }
-                               break;
-                       default:
-                               ipseclog((LOG_DEBUG,
-                                                 "key_parse: unsupported address family.\n"));
-                               PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
-                               error = EAFNOSUPPORT;
-                               goto senderror;
-               }
-               
-               switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
-                       case AF_INET:
-                               plen = sizeof(struct in_addr) << 3;
-                               break;
-                       case AF_INET6:
-                               plen = sizeof(struct in6_addr) << 3;
-                               break;
-                       default:
-                               plen = 0;       /*fool gcc*/
-                               break;
+
+               if (dst0 == NULL) {
+                       dst0 = mh.ext[SADB_X_EXT_ADDR_RANGE_DST_START];
                }
-               
-               /* check max prefix length */
-               if (src0->sadb_address_prefixlen > plen ||
-                   dst0->sadb_address_prefixlen > plen) {
-                       ipseclog((LOG_DEBUG,
-                                         "key_parse: illegal prefixlen.\n"));
-                       PFKEY_STAT_INCREMENT(pfkeystat.out_invaddr);
-                       error = EINVAL;
+       }
+       if (src0 != NULL && dst0 != NULL) {
+               error = key_validate_address_pair((struct sadb_address *)(src0),
+                                                                                 (struct sadb_address *)(dst0));
+               if (error != 0) {
                        goto senderror;
                }
-               
-               /*
-                * prefixlen == 0 is valid because there can be a case when
-                * all addresses are matched.
-                */
        }
        
        if (msg->sadb_msg_type >= sizeof(key_typesw)/sizeof(key_typesw[0]) ||
@@ -9514,10 +9612,6 @@ key_parse(
        
        error = (*key_typesw[msg->sadb_msg_type])(so, m, &mh);
 
-       // mh.ext points to the mbuf content.
-       // Zero out Encryption and Integrity keys if present.
-       bzero_keys(&mh);
-       
        return error;
 
 senderror:
@@ -9538,7 +9632,7 @@ key_senderror(
 {
        struct sadb_msg *msg;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        if (m->m_len < sizeof(struct sadb_msg))
                panic("invalid mbuf passed to key_senderror");
@@ -9679,7 +9773,7 @@ key_validate_ext(
 {
        struct sockaddr *sa;
        enum { NONE, ADDR } checktype = NONE;
-       int baselen;
+       int baselen = 0;
        const int sal = offsetof(struct sockaddr, sa_len) + sizeof(sa->sa_len);
        
        if (len != PFKEY_UNUNIT64(ext->sadb_ext_len))
@@ -9826,7 +9920,7 @@ key_sa_routechange(
        
        lck_mtx_lock(sadb_mutex);
        LIST_FOREACH(sah, &sahtree, chain) {
-               ro = &sah->sa_route;
+               ro = (struct route *)&sah->sa_route;
                if (ro->ro_rt && dst->sa_len == ro->ro_dst.sa_len
                        && bcmp(dst, &ro->ro_dst, dst->sa_len) == 0) {
                        ROUTE_RELEASE(ro);
@@ -9849,7 +9943,7 @@ key_sa_chgstate(
        if (sav->state == state)
                return;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_OWNED);
        
        if (__LIST_CHAINED(sav))
                LIST_REMOVE(sav, chain);
@@ -10007,7 +10101,7 @@ key_getsastat (struct socket *so,
                return key_senderror(so, m, EINVAL);
        }
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        // exit early if there are no active SAs
        if (ipsec_sav_count <= 0) {
@@ -10214,7 +10308,7 @@ key_delsp_for_ipsec_if (ifnet_t ipsec_if)
        if (ipsec_if == NULL)
         return;
        
-       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
+       LCK_MTX_ASSERT(sadb_mutex, LCK_MTX_ASSERT_NOTOWNED);
        
        lck_mtx_lock(sadb_mutex);