17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57845d282Sdanmcd * Common Development and Distribution License (the "License"). 67845d282Sdanmcd * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22930af642SDan McDonald * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/types.h> 277c478bd9Sstevel@tonic-gate #include <sys/stream.h> 287c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 297c478bd9Sstevel@tonic-gate #include <sys/errno.h> 307c478bd9Sstevel@tonic-gate #include <sys/strlog.h> 317c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 327c478bd9Sstevel@tonic-gate #include <sys/socket.h> 337c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 347c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 357c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 36f4b3ec61Sdh155122 #include <sys/zone.h> 377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 387c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 397c478bd9Sstevel@tonic-gate #include <sys/vtrace.h> 407c478bd9Sstevel@tonic-gate #include <sys/debug.h> 417c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 427c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 437c478bd9Sstevel@tonic-gate #include <sys/random.h> 447c478bd9Sstevel@tonic-gate #include <netinet/in.h> 457c478bd9Sstevel@tonic-gate #include <net/if.h> 467c478bd9Sstevel@tonic-gate #include <netinet/ip6.h> 477c478bd9Sstevel@tonic-gate #include <net/pfkeyv2.h> 48628b0c67SMark Fenwick #include <net/pfpolicy.h> 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #include <inet/common.h> 517c478bd9Sstevel@tonic-gate #include <inet/mi.h> 527c478bd9Sstevel@tonic-gate #include <inet/nd.h> 537c478bd9Sstevel@tonic-gate #include <inet/ip.h> 54437220cdSdanmcd #include <inet/ip_impl.h> 557c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 56bd670b35SErik Nordmark #include <inet/ip_if.h> 57bd670b35SErik Nordmark #include <inet/ip_ndp.h> 587c478bd9Sstevel@tonic-gate #include <inet/sadb.h> 597c478bd9Sstevel@tonic-gate #include <inet/ipsec_info.h> 607c478bd9Sstevel@tonic-gate #include <inet/ipsec_impl.h> 617c478bd9Sstevel@tonic-gate #include <inet/ipsecesp.h> 627c478bd9Sstevel@tonic-gate #include <inet/ipdrop.h> 637c478bd9Sstevel@tonic-gate #include <inet/tcp.h> 647c478bd9Sstevel@tonic-gate #include <sys/kstat.h> 657c478bd9Sstevel@tonic-gate #include <sys/policy.h> 667c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 675d3b8cb7SBill Sommerfeld #include <sys/strsubr.h> 687c478bd9Sstevel@tonic-gate #include <inet/udp_impl.h> 697c478bd9Sstevel@tonic-gate #include <sys/taskq.h> 70f4b3ec61Sdh155122 #include <sys/note.h> 717c478bd9Sstevel@tonic-gate 725d3b8cb7SBill Sommerfeld #include <sys/tsol/tnet.h> 735d3b8cb7SBill Sommerfeld 747c478bd9Sstevel@tonic-gate /* 757c478bd9Sstevel@tonic-gate * Table of ND variables supported by ipsecesp. These are loaded into 767c478bd9Sstevel@tonic-gate * ipsecesp_g_nd in ipsecesp_init_nd. 777c478bd9Sstevel@tonic-gate * All of these are alterable, within the min/max values given, at run time. 787c478bd9Sstevel@tonic-gate */ 79f4b3ec61Sdh155122 static ipsecespparam_t lcl_param_arr[] = { 807c478bd9Sstevel@tonic-gate /* min max value name */ 817c478bd9Sstevel@tonic-gate { 0, 3, 0, "ipsecesp_debug"}, 827c478bd9Sstevel@tonic-gate { 125, 32000, SADB_AGE_INTERVAL_DEFAULT, "ipsecesp_age_interval"}, 837c478bd9Sstevel@tonic-gate { 1, 10, 1, "ipsecesp_reap_delay"}, 847c478bd9Sstevel@tonic-gate { 1, SADB_MAX_REPLAY, 64, "ipsecesp_replay_size"}, 857c478bd9Sstevel@tonic-gate { 1, 300, 15, "ipsecesp_acquire_timeout"}, 867c478bd9Sstevel@tonic-gate { 1, 1800, 90, "ipsecesp_larval_timeout"}, 877c478bd9Sstevel@tonic-gate /* Default lifetime values for ACQUIRE messages. */ 887c478bd9Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_soft_bytes"}, 897c478bd9Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_hard_bytes"}, 907c478bd9Sstevel@tonic-gate { 0, 0xffffffffU, 24000, "ipsecesp_default_soft_addtime"}, 917c478bd9Sstevel@tonic-gate { 0, 0xffffffffU, 28800, "ipsecesp_default_hard_addtime"}, 927c478bd9Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_soft_usetime"}, 937c478bd9Sstevel@tonic-gate { 0, 0xffffffffU, 0, "ipsecesp_default_hard_usetime"}, 947c478bd9Sstevel@tonic-gate { 0, 1, 0, "ipsecesp_log_unknown_spi"}, 957c478bd9Sstevel@tonic-gate { 0, 2, 1, "ipsecesp_padding_check"}, 96437220cdSdanmcd { 0, 600, 20, "ipsecesp_nat_keepalive_interval"}, 977c478bd9Sstevel@tonic-gate }; 98f4b3ec61Sdh155122 #define ipsecesp_debug ipsecesp_params[0].ipsecesp_param_value 99f4b3ec61Sdh155122 #define ipsecesp_age_interval ipsecesp_params[1].ipsecesp_param_value 100f4b3ec61Sdh155122 #define ipsecesp_age_int_max ipsecesp_params[1].ipsecesp_param_max 101f4b3ec61Sdh155122 #define ipsecesp_reap_delay ipsecesp_params[2].ipsecesp_param_value 102f4b3ec61Sdh155122 #define ipsecesp_replay_size ipsecesp_params[3].ipsecesp_param_value 103f4b3ec61Sdh155122 #define ipsecesp_acquire_timeout \ 104f4b3ec61Sdh155122 ipsecesp_params[4].ipsecesp_param_value 105f4b3ec61Sdh155122 #define ipsecesp_larval_timeout \ 106f4b3ec61Sdh155122 ipsecesp_params[5].ipsecesp_param_value 1077c478bd9Sstevel@tonic-gate #define ipsecesp_default_soft_bytes \ 108f4b3ec61Sdh155122 ipsecesp_params[6].ipsecesp_param_value 1097c478bd9Sstevel@tonic-gate #define ipsecesp_default_hard_bytes \ 110f4b3ec61Sdh155122 ipsecesp_params[7].ipsecesp_param_value 1117c478bd9Sstevel@tonic-gate #define ipsecesp_default_soft_addtime \ 112f4b3ec61Sdh155122 ipsecesp_params[8].ipsecesp_param_value 1137c478bd9Sstevel@tonic-gate #define ipsecesp_default_hard_addtime \ 114f4b3ec61Sdh155122 ipsecesp_params[9].ipsecesp_param_value 1157c478bd9Sstevel@tonic-gate #define ipsecesp_default_soft_usetime \ 116f4b3ec61Sdh155122 ipsecesp_params[10].ipsecesp_param_value 1177c478bd9Sstevel@tonic-gate #define ipsecesp_default_hard_usetime \ 118f4b3ec61Sdh155122 ipsecesp_params[11].ipsecesp_param_value 1197c478bd9Sstevel@tonic-gate #define ipsecesp_log_unknown_spi \ 120f4b3ec61Sdh155122 ipsecesp_params[12].ipsecesp_param_value 1217c478bd9Sstevel@tonic-gate #define ipsecesp_padding_check \ 122f4b3ec61Sdh155122 ipsecesp_params[13].ipsecesp_param_value 123437220cdSdanmcd /* For ipsecesp_nat_keepalive_interval, see ipsecesp.h. */ 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate #define esp0dbg(a) printf a 1267c478bd9Sstevel@tonic-gate /* NOTE: != 0 instead of > 0 so lint doesn't complain. */ 127f4b3ec61Sdh155122 #define esp1dbg(espstack, a) if (espstack->ipsecesp_debug != 0) printf a 128f4b3ec61Sdh155122 #define esp2dbg(espstack, a) if (espstack->ipsecesp_debug > 1) printf a 129f4b3ec61Sdh155122 #define esp3dbg(espstack, a) if (espstack->ipsecesp_debug > 2) printf a 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate static int ipsecesp_open(queue_t *, dev_t *, int, int, cred_t *); 1327c478bd9Sstevel@tonic-gate static int ipsecesp_close(queue_t *); 1337c478bd9Sstevel@tonic-gate static void ipsecesp_wput(queue_t *, mblk_t *); 134f4b3ec61Sdh155122 static void *ipsecesp_stack_init(netstackid_t stackid, netstack_t *ns); 135f4b3ec61Sdh155122 static void ipsecesp_stack_fini(netstackid_t stackid, void *arg); 136f4b3ec61Sdh155122 static void esp_send_acquire(ipsacq_t *, mblk_t *, netstack_t *); 1377c478bd9Sstevel@tonic-gate 138437220cdSdanmcd static void esp_prepare_udp(netstack_t *, mblk_t *, ipha_t *); 139bd670b35SErik Nordmark static void esp_outbound_finish(mblk_t *, ip_xmit_attr_t *); 140bd670b35SErik Nordmark static void esp_inbound_restart(mblk_t *, ip_recv_attr_t *); 1417c478bd9Sstevel@tonic-gate 142f4b3ec61Sdh155122 static boolean_t esp_register_out(uint32_t, uint32_t, uint_t, 143bd670b35SErik Nordmark ipsecesp_stack_t *, cred_t *); 1447c478bd9Sstevel@tonic-gate static boolean_t esp_strip_header(mblk_t *, boolean_t, uint32_t, 145f4b3ec61Sdh155122 kstat_named_t **, ipsecesp_stack_t *); 146bd670b35SErik Nordmark static mblk_t *esp_submit_req_inbound(mblk_t *, ip_recv_attr_t *, 147bd670b35SErik Nordmark ipsa_t *, uint_t); 148bd670b35SErik Nordmark static mblk_t *esp_submit_req_outbound(mblk_t *, ip_xmit_attr_t *, 149bd670b35SErik Nordmark ipsa_t *, uchar_t *, uint_t); 1509c2c14abSThejaswini Singarajipura 151f4b3ec61Sdh155122 /* Setable in /etc/system */ 152f4b3ec61Sdh155122 uint32_t esp_hash_size = IPSEC_DEFAULT_HASH_SIZE; 153f4b3ec61Sdh155122 1547c478bd9Sstevel@tonic-gate static struct module_info info = { 1557c478bd9Sstevel@tonic-gate 5137, "ipsecesp", 0, INFPSZ, 65536, 1024 1567c478bd9Sstevel@tonic-gate }; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate static struct qinit rinit = { 159bd670b35SErik Nordmark (pfi_t)putnext, NULL, ipsecesp_open, ipsecesp_close, NULL, &info, 1607c478bd9Sstevel@tonic-gate NULL 1617c478bd9Sstevel@tonic-gate }; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate static struct qinit winit = { 1647c478bd9Sstevel@tonic-gate (pfi_t)ipsecesp_wput, NULL, ipsecesp_open, ipsecesp_close, NULL, &info, 1657c478bd9Sstevel@tonic-gate NULL 1667c478bd9Sstevel@tonic-gate }; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate struct streamtab ipsecespinfo = { 1697c478bd9Sstevel@tonic-gate &rinit, &winit, NULL, NULL 1707c478bd9Sstevel@tonic-gate }; 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate static taskq_t *esp_taskq; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate /* 1757c478bd9Sstevel@tonic-gate * OTOH, this one is set at open/close, and I'm D_MTQPAIR for now. 1767c478bd9Sstevel@tonic-gate * 1777c478bd9Sstevel@tonic-gate * Question: Do I need this, given that all instance's esps->esps_wq point 1787c478bd9Sstevel@tonic-gate * to IP? 1797c478bd9Sstevel@tonic-gate * 1807c478bd9Sstevel@tonic-gate * Answer: Yes, because I need to know which queue is BOUND to 1817c478bd9Sstevel@tonic-gate * IPPROTO_ESP 1827c478bd9Sstevel@tonic-gate */ 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate /* 1857c478bd9Sstevel@tonic-gate * Stats. This may eventually become a full-blown SNMP MIB once that spec 1867c478bd9Sstevel@tonic-gate * stabilizes. 1877c478bd9Sstevel@tonic-gate */ 1887c478bd9Sstevel@tonic-gate 189f4b3ec61Sdh155122 typedef struct esp_kstats_s { 1907c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_num_aalgs; 1917c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_good_auth; 1927c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_bad_auth; 1937c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_bad_padding; 1947c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_replay_failures; 1957c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_replay_early_failures; 1967c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_keysock_in; 1977c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_out_requests; 1987c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_acquire_requests; 1997c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_bytes_expired; 2007c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_out_discards; 2017c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_crypto_sync; 2027c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_crypto_async; 2037c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_crypto_failures; 2047c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_num_ealgs; 2057c478bd9Sstevel@tonic-gate kstat_named_t esp_stat_bad_decrypt; 2064a179720Sdanmcd kstat_named_t esp_stat_sa_port_renumbers; 2077c478bd9Sstevel@tonic-gate } esp_kstats_t; 2087c478bd9Sstevel@tonic-gate 209f4b3ec61Sdh155122 /* 210f4b3ec61Sdh155122 * espstack->esp_kstats is equal to espstack->esp_ksp->ks_data if 211f4b3ec61Sdh155122 * kstat_create_netstack for espstack->esp_ksp succeeds, but when it 212f4b3ec61Sdh155122 * fails, it will be NULL. Note this is done for all stack instances, 213f4b3ec61Sdh155122 * so it *could* fail. hence a non-NULL checking is done for 214f4b3ec61Sdh155122 * ESP_BUMP_STAT and ESP_DEBUMP_STAT 215f4b3ec61Sdh155122 */ 216f4b3ec61Sdh155122 #define ESP_BUMP_STAT(espstack, x) \ 217f4b3ec61Sdh155122 do { \ 218f4b3ec61Sdh155122 if (espstack->esp_kstats != NULL) \ 219f4b3ec61Sdh155122 (espstack->esp_kstats->esp_stat_ ## x).value.ui64++; \ 220f4b3ec61Sdh155122 _NOTE(CONSTCOND) \ 221f4b3ec61Sdh155122 } while (0) 2227c478bd9Sstevel@tonic-gate 223f4b3ec61Sdh155122 #define ESP_DEBUMP_STAT(espstack, x) \ 224f4b3ec61Sdh155122 do { \ 225f4b3ec61Sdh155122 if (espstack->esp_kstats != NULL) \ 226f4b3ec61Sdh155122 (espstack->esp_kstats->esp_stat_ ## x).value.ui64--; \ 227f4b3ec61Sdh155122 _NOTE(CONSTCOND) \ 228f4b3ec61Sdh155122 } while (0) 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate static int esp_kstat_update(kstat_t *, int); 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate static boolean_t 233f4b3ec61Sdh155122 esp_kstat_init(ipsecesp_stack_t *espstack, netstackid_t stackid) 2347c478bd9Sstevel@tonic-gate { 235f4b3ec61Sdh155122 espstack->esp_ksp = kstat_create_netstack("ipsecesp", 0, "esp_stat", 236f4b3ec61Sdh155122 "net", KSTAT_TYPE_NAMED, 237f4b3ec61Sdh155122 sizeof (esp_kstats_t) / sizeof (kstat_named_t), 238f4b3ec61Sdh155122 KSTAT_FLAG_PERSISTENT, stackid); 2397c478bd9Sstevel@tonic-gate 240f4b3ec61Sdh155122 if (espstack->esp_ksp == NULL || espstack->esp_ksp->ks_data == NULL) 2417c478bd9Sstevel@tonic-gate return (B_FALSE); 2427c478bd9Sstevel@tonic-gate 243f4b3ec61Sdh155122 espstack->esp_kstats = espstack->esp_ksp->ks_data; 2447c478bd9Sstevel@tonic-gate 245f4b3ec61Sdh155122 espstack->esp_ksp->ks_update = esp_kstat_update; 246f4b3ec61Sdh155122 espstack->esp_ksp->ks_private = (void *)(uintptr_t)stackid; 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate #define K64 KSTAT_DATA_UINT64 249f4b3ec61Sdh155122 #define KI(x) kstat_named_init(&(espstack->esp_kstats->esp_stat_##x), #x, K64) 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate KI(num_aalgs); 2527c478bd9Sstevel@tonic-gate KI(num_ealgs); 2537c478bd9Sstevel@tonic-gate KI(good_auth); 2547c478bd9Sstevel@tonic-gate KI(bad_auth); 2557c478bd9Sstevel@tonic-gate KI(bad_padding); 2567c478bd9Sstevel@tonic-gate KI(replay_failures); 2577c478bd9Sstevel@tonic-gate KI(replay_early_failures); 2587c478bd9Sstevel@tonic-gate KI(keysock_in); 2597c478bd9Sstevel@tonic-gate KI(out_requests); 2607c478bd9Sstevel@tonic-gate KI(acquire_requests); 2617c478bd9Sstevel@tonic-gate KI(bytes_expired); 2627c478bd9Sstevel@tonic-gate KI(out_discards); 2637c478bd9Sstevel@tonic-gate KI(crypto_sync); 2647c478bd9Sstevel@tonic-gate KI(crypto_async); 2657c478bd9Sstevel@tonic-gate KI(crypto_failures); 2667c478bd9Sstevel@tonic-gate KI(bad_decrypt); 2674a179720Sdanmcd KI(sa_port_renumbers); 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate #undef KI 2707c478bd9Sstevel@tonic-gate #undef K64 2717c478bd9Sstevel@tonic-gate 272f4b3ec61Sdh155122 kstat_install(espstack->esp_ksp); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate return (B_TRUE); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate static int 2787c478bd9Sstevel@tonic-gate esp_kstat_update(kstat_t *kp, int rw) 2797c478bd9Sstevel@tonic-gate { 2807c478bd9Sstevel@tonic-gate esp_kstats_t *ekp; 281f4b3ec61Sdh155122 netstackid_t stackid = (zoneid_t)(uintptr_t)kp->ks_private; 282f4b3ec61Sdh155122 netstack_t *ns; 283f4b3ec61Sdh155122 ipsec_stack_t *ipss; 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate if ((kp == NULL) || (kp->ks_data == NULL)) 2867c478bd9Sstevel@tonic-gate return (EIO); 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate if (rw == KSTAT_WRITE) 2897c478bd9Sstevel@tonic-gate return (EACCES); 2907c478bd9Sstevel@tonic-gate 291f4b3ec61Sdh155122 ns = netstack_find_by_stackid(stackid); 292f4b3ec61Sdh155122 if (ns == NULL) 293f4b3ec61Sdh155122 return (-1); 294f4b3ec61Sdh155122 ipss = ns->netstack_ipsec; 295f4b3ec61Sdh155122 if (ipss == NULL) { 296f4b3ec61Sdh155122 netstack_rele(ns); 297f4b3ec61Sdh155122 return (-1); 298f4b3ec61Sdh155122 } 2997c478bd9Sstevel@tonic-gate ekp = (esp_kstats_t *)kp->ks_data; 3007c478bd9Sstevel@tonic-gate 301f4b3ec61Sdh155122 mutex_enter(&ipss->ipsec_alg_lock); 302f4b3ec61Sdh155122 ekp->esp_stat_num_aalgs.value.ui64 = 303f4b3ec61Sdh155122 ipss->ipsec_nalgs[IPSEC_ALG_AUTH]; 304f4b3ec61Sdh155122 ekp->esp_stat_num_ealgs.value.ui64 = 305f4b3ec61Sdh155122 ipss->ipsec_nalgs[IPSEC_ALG_ENCR]; 306f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 3077c478bd9Sstevel@tonic-gate 308f4b3ec61Sdh155122 netstack_rele(ns); 3097c478bd9Sstevel@tonic-gate return (0); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate #ifdef DEBUG 3137c478bd9Sstevel@tonic-gate /* 3147c478bd9Sstevel@tonic-gate * Debug routine, useful to see pre-encryption data. 3157c478bd9Sstevel@tonic-gate */ 3167c478bd9Sstevel@tonic-gate static char * 3177c478bd9Sstevel@tonic-gate dump_msg(mblk_t *mp) 3187c478bd9Sstevel@tonic-gate { 3197c478bd9Sstevel@tonic-gate char tmp_str[3], tmp_line[256]; 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate while (mp != NULL) { 3227c478bd9Sstevel@tonic-gate unsigned char *ptr; 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate printf("mblk address 0x%p, length %ld, db_ref %d " 3257c478bd9Sstevel@tonic-gate "type %d, base 0x%p, lim 0x%p\n", 3267c478bd9Sstevel@tonic-gate (void *) mp, (long)(mp->b_wptr - mp->b_rptr), 3277c478bd9Sstevel@tonic-gate mp->b_datap->db_ref, mp->b_datap->db_type, 3287c478bd9Sstevel@tonic-gate (void *)mp->b_datap->db_base, (void *)mp->b_datap->db_lim); 3297c478bd9Sstevel@tonic-gate ptr = mp->b_rptr; 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate tmp_line[0] = '\0'; 3327c478bd9Sstevel@tonic-gate while (ptr < mp->b_wptr) { 3337c478bd9Sstevel@tonic-gate uint_t diff; 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate diff = (ptr - mp->b_rptr); 3367c478bd9Sstevel@tonic-gate if (!(diff & 0x1f)) { 3377c478bd9Sstevel@tonic-gate if (strlen(tmp_line) > 0) { 3387c478bd9Sstevel@tonic-gate printf("bytes: %s\n", tmp_line); 3397c478bd9Sstevel@tonic-gate tmp_line[0] = '\0'; 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate } 3427c478bd9Sstevel@tonic-gate if (!(diff & 0x3)) 3437c478bd9Sstevel@tonic-gate (void) strcat(tmp_line, " "); 3447c478bd9Sstevel@tonic-gate (void) sprintf(tmp_str, "%02x", *ptr); 3457c478bd9Sstevel@tonic-gate (void) strcat(tmp_line, tmp_str); 3467c478bd9Sstevel@tonic-gate ptr++; 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate if (strlen(tmp_line) > 0) 3497c478bd9Sstevel@tonic-gate printf("bytes: %s\n", tmp_line); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate mp = mp->b_cont; 3527c478bd9Sstevel@tonic-gate } 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate return ("\n"); 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate #else /* DEBUG */ 3587c478bd9Sstevel@tonic-gate static char * 3597c478bd9Sstevel@tonic-gate dump_msg(mblk_t *mp) 3607c478bd9Sstevel@tonic-gate { 3617c478bd9Sstevel@tonic-gate printf("Find value of mp %p.\n", mp); 3627c478bd9Sstevel@tonic-gate return ("\n"); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate /* 3677c478bd9Sstevel@tonic-gate * Don't have to lock age_interval, as only one thread will access it at 3687c478bd9Sstevel@tonic-gate * a time, because I control the one function that does with timeout(). 3697c478bd9Sstevel@tonic-gate */ 3707c478bd9Sstevel@tonic-gate static void 371f4b3ec61Sdh155122 esp_ager(void *arg) 3727c478bd9Sstevel@tonic-gate { 373f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)arg; 374f4b3ec61Sdh155122 netstack_t *ns = espstack->ipsecesp_netstack; 3757c478bd9Sstevel@tonic-gate hrtime_t begin = gethrtime(); 3767c478bd9Sstevel@tonic-gate 377f4b3ec61Sdh155122 sadb_ager(&espstack->esp_sadb.s_v4, espstack->esp_pfkey_q, 378bd670b35SErik Nordmark espstack->ipsecesp_reap_delay, ns); 379f4b3ec61Sdh155122 sadb_ager(&espstack->esp_sadb.s_v6, espstack->esp_pfkey_q, 380bd670b35SErik Nordmark espstack->ipsecesp_reap_delay, ns); 3817c478bd9Sstevel@tonic-gate 382f4b3ec61Sdh155122 espstack->esp_event = sadb_retimeout(begin, espstack->esp_pfkey_q, 383f4b3ec61Sdh155122 esp_ager, espstack, 384f4b3ec61Sdh155122 &espstack->ipsecesp_age_interval, espstack->ipsecesp_age_int_max, 385f4b3ec61Sdh155122 info.mi_idnum); 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate /* 3897c478bd9Sstevel@tonic-gate * Get an ESP NDD parameter. 3907c478bd9Sstevel@tonic-gate */ 3917c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3927c478bd9Sstevel@tonic-gate static int 3937c478bd9Sstevel@tonic-gate ipsecesp_param_get(q, mp, cp, cr) 3947c478bd9Sstevel@tonic-gate queue_t *q; 3957c478bd9Sstevel@tonic-gate mblk_t *mp; 3967c478bd9Sstevel@tonic-gate caddr_t cp; 3977c478bd9Sstevel@tonic-gate cred_t *cr; 3987c478bd9Sstevel@tonic-gate { 3997c478bd9Sstevel@tonic-gate ipsecespparam_t *ipsecesppa = (ipsecespparam_t *)cp; 4007c478bd9Sstevel@tonic-gate uint_t value; 401f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)q->q_ptr; 4027c478bd9Sstevel@tonic-gate 403f4b3ec61Sdh155122 mutex_enter(&espstack->ipsecesp_param_lock); 4047c478bd9Sstevel@tonic-gate value = ipsecesppa->ipsecesp_param_value; 405f4b3ec61Sdh155122 mutex_exit(&espstack->ipsecesp_param_lock); 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, "%u", value); 4087c478bd9Sstevel@tonic-gate return (0); 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate /* 4127c478bd9Sstevel@tonic-gate * This routine sets an NDD variable in a ipsecespparam_t structure. 4137c478bd9Sstevel@tonic-gate */ 4147c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4157c478bd9Sstevel@tonic-gate static int 4167c478bd9Sstevel@tonic-gate ipsecesp_param_set(q, mp, value, cp, cr) 4177c478bd9Sstevel@tonic-gate queue_t *q; 4187c478bd9Sstevel@tonic-gate mblk_t *mp; 4197c478bd9Sstevel@tonic-gate char *value; 4207c478bd9Sstevel@tonic-gate caddr_t cp; 4217c478bd9Sstevel@tonic-gate cred_t *cr; 4227c478bd9Sstevel@tonic-gate { 4237c478bd9Sstevel@tonic-gate ulong_t new_value; 4247c478bd9Sstevel@tonic-gate ipsecespparam_t *ipsecesppa = (ipsecespparam_t *)cp; 425f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)q->q_ptr; 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate /* 4287c478bd9Sstevel@tonic-gate * Fail the request if the new value does not lie within the 4297c478bd9Sstevel@tonic-gate * required bounds. 4307c478bd9Sstevel@tonic-gate */ 4317c478bd9Sstevel@tonic-gate if (ddi_strtoul(value, NULL, 10, &new_value) != 0 || 4327c478bd9Sstevel@tonic-gate new_value < ipsecesppa->ipsecesp_param_min || 4337c478bd9Sstevel@tonic-gate new_value > ipsecesppa->ipsecesp_param_max) { 4347c478bd9Sstevel@tonic-gate return (EINVAL); 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate /* Set the new value */ 438f4b3ec61Sdh155122 mutex_enter(&espstack->ipsecesp_param_lock); 4397c478bd9Sstevel@tonic-gate ipsecesppa->ipsecesp_param_value = new_value; 440f4b3ec61Sdh155122 mutex_exit(&espstack->ipsecesp_param_lock); 4417c478bd9Sstevel@tonic-gate return (0); 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate /* 4457c478bd9Sstevel@tonic-gate * Using lifetime NDD variables, fill in an extended combination's 4467c478bd9Sstevel@tonic-gate * lifetime information. 4477c478bd9Sstevel@tonic-gate */ 4487c478bd9Sstevel@tonic-gate void 449f4b3ec61Sdh155122 ipsecesp_fill_defs(sadb_x_ecomb_t *ecomb, netstack_t *ns) 4507c478bd9Sstevel@tonic-gate { 451f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 452f4b3ec61Sdh155122 453f4b3ec61Sdh155122 ecomb->sadb_x_ecomb_soft_bytes = espstack->ipsecesp_default_soft_bytes; 454f4b3ec61Sdh155122 ecomb->sadb_x_ecomb_hard_bytes = espstack->ipsecesp_default_hard_bytes; 455f4b3ec61Sdh155122 ecomb->sadb_x_ecomb_soft_addtime = 456f4b3ec61Sdh155122 espstack->ipsecesp_default_soft_addtime; 457f4b3ec61Sdh155122 ecomb->sadb_x_ecomb_hard_addtime = 458f4b3ec61Sdh155122 espstack->ipsecesp_default_hard_addtime; 459f4b3ec61Sdh155122 ecomb->sadb_x_ecomb_soft_usetime = 460f4b3ec61Sdh155122 espstack->ipsecesp_default_soft_usetime; 461f4b3ec61Sdh155122 ecomb->sadb_x_ecomb_hard_usetime = 462f4b3ec61Sdh155122 espstack->ipsecesp_default_hard_usetime; 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate /* 4667c478bd9Sstevel@tonic-gate * Initialize things for ESP at module load time. 4677c478bd9Sstevel@tonic-gate */ 4687c478bd9Sstevel@tonic-gate boolean_t 4697c478bd9Sstevel@tonic-gate ipsecesp_ddi_init(void) 4707c478bd9Sstevel@tonic-gate { 4717c478bd9Sstevel@tonic-gate esp_taskq = taskq_create("esp_taskq", 1, minclsyspri, 4727c478bd9Sstevel@tonic-gate IPSEC_TASKQ_MIN, IPSEC_TASKQ_MAX, 0); 4737c478bd9Sstevel@tonic-gate 474f4b3ec61Sdh155122 /* 475f4b3ec61Sdh155122 * We want to be informed each time a stack is created or 476f4b3ec61Sdh155122 * destroyed in the kernel, so we can maintain the 477f4b3ec61Sdh155122 * set of ipsecesp_stack_t's. 478f4b3ec61Sdh155122 */ 479f4b3ec61Sdh155122 netstack_register(NS_IPSECESP, ipsecesp_stack_init, NULL, 480f4b3ec61Sdh155122 ipsecesp_stack_fini); 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate return (B_TRUE); 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate /* 486f4b3ec61Sdh155122 * Walk through the param array specified registering each element with the 487f4b3ec61Sdh155122 * named dispatch handler. 488f4b3ec61Sdh155122 */ 489f4b3ec61Sdh155122 static boolean_t 490f4b3ec61Sdh155122 ipsecesp_param_register(IDP *ndp, ipsecespparam_t *espp, int cnt) 491f4b3ec61Sdh155122 { 492f4b3ec61Sdh155122 for (; cnt-- > 0; espp++) { 493f4b3ec61Sdh155122 if (espp->ipsecesp_param_name != NULL && 494f4b3ec61Sdh155122 espp->ipsecesp_param_name[0]) { 495f4b3ec61Sdh155122 if (!nd_load(ndp, 496f4b3ec61Sdh155122 espp->ipsecesp_param_name, 497f4b3ec61Sdh155122 ipsecesp_param_get, ipsecesp_param_set, 498f4b3ec61Sdh155122 (caddr_t)espp)) { 499f4b3ec61Sdh155122 nd_free(ndp); 500f4b3ec61Sdh155122 return (B_FALSE); 501f4b3ec61Sdh155122 } 502f4b3ec61Sdh155122 } 503f4b3ec61Sdh155122 } 504f4b3ec61Sdh155122 return (B_TRUE); 505f4b3ec61Sdh155122 } 506f4b3ec61Sdh155122 /* 507f4b3ec61Sdh155122 * Initialize things for ESP for each stack instance 508f4b3ec61Sdh155122 */ 509f4b3ec61Sdh155122 static void * 510f4b3ec61Sdh155122 ipsecesp_stack_init(netstackid_t stackid, netstack_t *ns) 511f4b3ec61Sdh155122 { 512f4b3ec61Sdh155122 ipsecesp_stack_t *espstack; 513f4b3ec61Sdh155122 ipsecespparam_t *espp; 514f4b3ec61Sdh155122 515f4b3ec61Sdh155122 espstack = (ipsecesp_stack_t *)kmem_zalloc(sizeof (*espstack), 516f4b3ec61Sdh155122 KM_SLEEP); 517f4b3ec61Sdh155122 espstack->ipsecesp_netstack = ns; 518f4b3ec61Sdh155122 519f4b3ec61Sdh155122 espp = (ipsecespparam_t *)kmem_alloc(sizeof (lcl_param_arr), KM_SLEEP); 520f4b3ec61Sdh155122 espstack->ipsecesp_params = espp; 521f4b3ec61Sdh155122 bcopy(lcl_param_arr, espp, sizeof (lcl_param_arr)); 522f4b3ec61Sdh155122 523f4b3ec61Sdh155122 (void) ipsecesp_param_register(&espstack->ipsecesp_g_nd, espp, 524f4b3ec61Sdh155122 A_CNT(lcl_param_arr)); 525f4b3ec61Sdh155122 526f4b3ec61Sdh155122 (void) esp_kstat_init(espstack, stackid); 527f4b3ec61Sdh155122 528f4b3ec61Sdh155122 espstack->esp_sadb.s_acquire_timeout = 529f4b3ec61Sdh155122 &espstack->ipsecesp_acquire_timeout; 530f4b3ec61Sdh155122 espstack->esp_sadb.s_acqfn = esp_send_acquire; 531f4b3ec61Sdh155122 sadbp_init("ESP", &espstack->esp_sadb, SADB_SATYPE_ESP, esp_hash_size, 532f4b3ec61Sdh155122 espstack->ipsecesp_netstack); 533f4b3ec61Sdh155122 534f4b3ec61Sdh155122 mutex_init(&espstack->ipsecesp_param_lock, NULL, MUTEX_DEFAULT, 0); 535f4b3ec61Sdh155122 536f4b3ec61Sdh155122 ip_drop_register(&espstack->esp_dropper, "IPsec ESP"); 537f4b3ec61Sdh155122 return (espstack); 538f4b3ec61Sdh155122 } 539f4b3ec61Sdh155122 540f4b3ec61Sdh155122 /* 5417c478bd9Sstevel@tonic-gate * Destroy things for ESP at module unload time. 5427c478bd9Sstevel@tonic-gate */ 5437c478bd9Sstevel@tonic-gate void 5447c478bd9Sstevel@tonic-gate ipsecesp_ddi_destroy(void) 5457c478bd9Sstevel@tonic-gate { 546f4b3ec61Sdh155122 netstack_unregister(NS_IPSECESP); 5477c478bd9Sstevel@tonic-gate taskq_destroy(esp_taskq); 548f4b3ec61Sdh155122 } 549f4b3ec61Sdh155122 550f4b3ec61Sdh155122 /* 551f4b3ec61Sdh155122 * Destroy things for ESP for one stack instance 552f4b3ec61Sdh155122 */ 553f4b3ec61Sdh155122 static void 554f4b3ec61Sdh155122 ipsecesp_stack_fini(netstackid_t stackid, void *arg) 555f4b3ec61Sdh155122 { 556f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)arg; 557f4b3ec61Sdh155122 558f4b3ec61Sdh155122 if (espstack->esp_pfkey_q != NULL) { 559f4b3ec61Sdh155122 (void) quntimeout(espstack->esp_pfkey_q, espstack->esp_event); 560f4b3ec61Sdh155122 } 561f4b3ec61Sdh155122 espstack->esp_sadb.s_acqfn = NULL; 562f4b3ec61Sdh155122 espstack->esp_sadb.s_acquire_timeout = NULL; 563f4b3ec61Sdh155122 sadbp_destroy(&espstack->esp_sadb, espstack->ipsecesp_netstack); 564f4b3ec61Sdh155122 ip_drop_unregister(&espstack->esp_dropper); 565f4b3ec61Sdh155122 mutex_destroy(&espstack->ipsecesp_param_lock); 566f4b3ec61Sdh155122 nd_free(&espstack->ipsecesp_g_nd); 567f4b3ec61Sdh155122 568f4b3ec61Sdh155122 kmem_free(espstack->ipsecesp_params, sizeof (lcl_param_arr)); 569f4b3ec61Sdh155122 espstack->ipsecesp_params = NULL; 570f4b3ec61Sdh155122 kstat_delete_netstack(espstack->esp_ksp, stackid); 571f4b3ec61Sdh155122 espstack->esp_ksp = NULL; 572f4b3ec61Sdh155122 espstack->esp_kstats = NULL; 573f4b3ec61Sdh155122 kmem_free(espstack, sizeof (*espstack)); 5747c478bd9Sstevel@tonic-gate } 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate /* 577bd670b35SErik Nordmark * ESP module open routine, which is here for keysock plumbing. 578bd670b35SErik Nordmark * Keysock is pushed over {AH,ESP} which is an artifact from the Bad Old 579bd670b35SErik Nordmark * Days of export control, and fears that ESP would not be allowed 580bd670b35SErik Nordmark * to be shipped at all by default. Eventually, keysock should 581bd670b35SErik Nordmark * either access AH and ESP via modstubs or krtld dependencies, or 582bd670b35SErik Nordmark * perhaps be folded in with AH and ESP into a single IPsec/netsec 583bd670b35SErik Nordmark * module ("netsec" if PF_KEY provides more than AH/ESP keying tables). 5847c478bd9Sstevel@tonic-gate */ 5857c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5867c478bd9Sstevel@tonic-gate static int 5877c478bd9Sstevel@tonic-gate ipsecesp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 5887c478bd9Sstevel@tonic-gate { 589f4b3ec61Sdh155122 netstack_t *ns; 590f4b3ec61Sdh155122 ipsecesp_stack_t *espstack; 591f4b3ec61Sdh155122 592d2370ffeSsommerfe if (secpolicy_ip_config(credp, B_FALSE) != 0) 5937c478bd9Sstevel@tonic-gate return (EPERM); 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate if (q->q_ptr != NULL) 5967c478bd9Sstevel@tonic-gate return (0); /* Re-open of an already open instance. */ 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate if (sflag != MODOPEN) 5997c478bd9Sstevel@tonic-gate return (EINVAL); 6007c478bd9Sstevel@tonic-gate 601f4b3ec61Sdh155122 ns = netstack_find_by_cred(credp); 602f4b3ec61Sdh155122 ASSERT(ns != NULL); 603f4b3ec61Sdh155122 espstack = ns->netstack_ipsecesp; 604f4b3ec61Sdh155122 ASSERT(espstack != NULL); 605f4b3ec61Sdh155122 606f4b3ec61Sdh155122 q->q_ptr = espstack; 607f4b3ec61Sdh155122 WR(q)->q_ptr = q->q_ptr; 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate qprocson(q); 6107c478bd9Sstevel@tonic-gate return (0); 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate /* 6147c478bd9Sstevel@tonic-gate * ESP module close routine. 6157c478bd9Sstevel@tonic-gate */ 6167c478bd9Sstevel@tonic-gate static int 6177c478bd9Sstevel@tonic-gate ipsecesp_close(queue_t *q) 6187c478bd9Sstevel@tonic-gate { 619f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)q->q_ptr; 620f4b3ec61Sdh155122 6217c478bd9Sstevel@tonic-gate /* 6227c478bd9Sstevel@tonic-gate * Clean up q_ptr, if needed. 6237c478bd9Sstevel@tonic-gate */ 6247c478bd9Sstevel@tonic-gate qprocsoff(q); 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate /* Keysock queue check is safe, because of OCEXCL perimeter. */ 6277c478bd9Sstevel@tonic-gate 628f4b3ec61Sdh155122 if (q == espstack->esp_pfkey_q) { 629f4b3ec61Sdh155122 esp1dbg(espstack, 630f4b3ec61Sdh155122 ("ipsecesp_close: Ummm... keysock is closing ESP.\n")); 631f4b3ec61Sdh155122 espstack->esp_pfkey_q = NULL; 6327c478bd9Sstevel@tonic-gate /* Detach qtimeouts. */ 633f4b3ec61Sdh155122 (void) quntimeout(q, espstack->esp_event); 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate 636f4b3ec61Sdh155122 netstack_rele(espstack->ipsecesp_netstack); 6377c478bd9Sstevel@tonic-gate return (0); 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate /* 6417c478bd9Sstevel@tonic-gate * Add a number of bytes to what the SA has protected so far. Return 6427c478bd9Sstevel@tonic-gate * B_TRUE if the SA can still protect that many bytes. 6437c478bd9Sstevel@tonic-gate * 6447c478bd9Sstevel@tonic-gate * Caller must REFRELE the passed-in assoc. This function must REFRELE 6457c478bd9Sstevel@tonic-gate * any obtained peer SA. 6467c478bd9Sstevel@tonic-gate */ 6477c478bd9Sstevel@tonic-gate static boolean_t 6487c478bd9Sstevel@tonic-gate esp_age_bytes(ipsa_t *assoc, uint64_t bytes, boolean_t inbound) 6497c478bd9Sstevel@tonic-gate { 6507c478bd9Sstevel@tonic-gate ipsa_t *inassoc, *outassoc; 6517c478bd9Sstevel@tonic-gate isaf_t *bucket; 6527c478bd9Sstevel@tonic-gate boolean_t inrc, outrc, isv6; 6537c478bd9Sstevel@tonic-gate sadb_t *sp; 6547c478bd9Sstevel@tonic-gate int outhash; 655f4b3ec61Sdh155122 netstack_t *ns = assoc->ipsa_netstack; 656f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate /* No peer? No problem! */ 6597c478bd9Sstevel@tonic-gate if (!assoc->ipsa_haspeer) { 660f4b3ec61Sdh155122 return (sadb_age_bytes(espstack->esp_pfkey_q, assoc, bytes, 6617c478bd9Sstevel@tonic-gate B_TRUE)); 6627c478bd9Sstevel@tonic-gate } 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate /* 6657c478bd9Sstevel@tonic-gate * Otherwise, we want to grab both the original assoc and its peer. 6667c478bd9Sstevel@tonic-gate * There might be a race for this, but if it's a real race, two 6677c478bd9Sstevel@tonic-gate * expire messages may occur. We limit this by only sending the 6687c478bd9Sstevel@tonic-gate * expire message on one of the peers, we'll pick the inbound 6697c478bd9Sstevel@tonic-gate * arbitrarily. 6707c478bd9Sstevel@tonic-gate * 6717c478bd9Sstevel@tonic-gate * If we need tight synchronization on the peer SA, then we need to 6727c478bd9Sstevel@tonic-gate * reconsider. 6737c478bd9Sstevel@tonic-gate */ 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate /* Use address length to select IPv6/IPv4 */ 6767c478bd9Sstevel@tonic-gate isv6 = (assoc->ipsa_addrfam == AF_INET6); 677f4b3ec61Sdh155122 sp = isv6 ? &espstack->esp_sadb.s_v6 : &espstack->esp_sadb.s_v4; 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate if (inbound) { 6807c478bd9Sstevel@tonic-gate inassoc = assoc; 6817c478bd9Sstevel@tonic-gate if (isv6) { 682fb87b5d2Ssommerfe outhash = OUTBOUND_HASH_V6(sp, *((in6_addr_t *) 6837c478bd9Sstevel@tonic-gate &inassoc->ipsa_dstaddr)); 6847c478bd9Sstevel@tonic-gate } else { 685fb87b5d2Ssommerfe outhash = OUTBOUND_HASH_V4(sp, *((ipaddr_t *) 6867c478bd9Sstevel@tonic-gate &inassoc->ipsa_dstaddr)); 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate bucket = &sp->sdb_of[outhash]; 6897c478bd9Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 6907c478bd9Sstevel@tonic-gate outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi, 6917c478bd9Sstevel@tonic-gate inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr, 6927c478bd9Sstevel@tonic-gate inassoc->ipsa_addrfam); 6937c478bd9Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 6947c478bd9Sstevel@tonic-gate if (outassoc == NULL) { 6957c478bd9Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 6967c478bd9Sstevel@tonic-gate esp0dbg(("esp_age_bytes: " 6977c478bd9Sstevel@tonic-gate "can't find peer for inbound.\n")); 698f4b3ec61Sdh155122 return (sadb_age_bytes(espstack->esp_pfkey_q, inassoc, 6997c478bd9Sstevel@tonic-gate bytes, B_TRUE)); 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate } else { 7027c478bd9Sstevel@tonic-gate outassoc = assoc; 703fb87b5d2Ssommerfe bucket = INBOUND_BUCKET(sp, outassoc->ipsa_spi); 7047c478bd9Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 7057c478bd9Sstevel@tonic-gate inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi, 7067c478bd9Sstevel@tonic-gate outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr, 7077c478bd9Sstevel@tonic-gate outassoc->ipsa_addrfam); 7087c478bd9Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 7097c478bd9Sstevel@tonic-gate if (inassoc == NULL) { 7107c478bd9Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 7117c478bd9Sstevel@tonic-gate esp0dbg(("esp_age_bytes: " 7127c478bd9Sstevel@tonic-gate "can't find peer for outbound.\n")); 713f4b3ec61Sdh155122 return (sadb_age_bytes(espstack->esp_pfkey_q, outassoc, 7147c478bd9Sstevel@tonic-gate bytes, B_TRUE)); 7157c478bd9Sstevel@tonic-gate } 7167c478bd9Sstevel@tonic-gate } 7177c478bd9Sstevel@tonic-gate 718f4b3ec61Sdh155122 inrc = sadb_age_bytes(espstack->esp_pfkey_q, inassoc, bytes, B_TRUE); 719f4b3ec61Sdh155122 outrc = sadb_age_bytes(espstack->esp_pfkey_q, outassoc, bytes, B_FALSE); 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate /* 7227c478bd9Sstevel@tonic-gate * REFRELE any peer SA. 7237c478bd9Sstevel@tonic-gate * 7247c478bd9Sstevel@tonic-gate * Because of the multi-line macro nature of IPSA_REFRELE, keep 7257c478bd9Sstevel@tonic-gate * them in { }. 7267c478bd9Sstevel@tonic-gate */ 7277c478bd9Sstevel@tonic-gate if (inbound) { 7287c478bd9Sstevel@tonic-gate IPSA_REFRELE(outassoc); 7297c478bd9Sstevel@tonic-gate } else { 7307c478bd9Sstevel@tonic-gate IPSA_REFRELE(inassoc); 7317c478bd9Sstevel@tonic-gate } 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate return (inrc && outrc); 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate /* 7377c478bd9Sstevel@tonic-gate * Do incoming NAT-T manipulations for packet. 738bd670b35SErik Nordmark * Returns NULL if the mblk chain is consumed. 7397c478bd9Sstevel@tonic-gate */ 740bd670b35SErik Nordmark static mblk_t * 7417c478bd9Sstevel@tonic-gate esp_fix_natt_checksums(mblk_t *data_mp, ipsa_t *assoc) 7427c478bd9Sstevel@tonic-gate { 7437c478bd9Sstevel@tonic-gate ipha_t *ipha = (ipha_t *)data_mp->b_rptr; 744bd670b35SErik Nordmark tcpha_t *tcpha; 7457c478bd9Sstevel@tonic-gate udpha_t *udpha; 7467c478bd9Sstevel@tonic-gate /* Initialize to our inbound cksum adjustment... */ 7477c478bd9Sstevel@tonic-gate uint32_t sum = assoc->ipsa_inbound_cksum; 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate switch (ipha->ipha_protocol) { 7507c478bd9Sstevel@tonic-gate case IPPROTO_TCP: 751bd670b35SErik Nordmark tcpha = (tcpha_t *)(data_mp->b_rptr + 7527c478bd9Sstevel@tonic-gate IPH_HDR_LENGTH(ipha)); 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate #define DOWN_SUM(x) (x) = ((x) & 0xFFFF) + ((x) >> 16) 755bd670b35SErik Nordmark sum += ~ntohs(tcpha->tha_sum) & 0xFFFF; 7567c478bd9Sstevel@tonic-gate DOWN_SUM(sum); 7577c478bd9Sstevel@tonic-gate DOWN_SUM(sum); 758bd670b35SErik Nordmark tcpha->tha_sum = ~htons(sum); 7597c478bd9Sstevel@tonic-gate break; 7607c478bd9Sstevel@tonic-gate case IPPROTO_UDP: 7617c478bd9Sstevel@tonic-gate udpha = (udpha_t *)(data_mp->b_rptr + IPH_HDR_LENGTH(ipha)); 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate if (udpha->uha_checksum != 0) { 7647c478bd9Sstevel@tonic-gate /* Adujst if the inbound one was not zero. */ 7657c478bd9Sstevel@tonic-gate sum += ~ntohs(udpha->uha_checksum) & 0xFFFF; 7667c478bd9Sstevel@tonic-gate DOWN_SUM(sum); 7677c478bd9Sstevel@tonic-gate DOWN_SUM(sum); 7687c478bd9Sstevel@tonic-gate udpha->uha_checksum = ~htons(sum); 7697c478bd9Sstevel@tonic-gate if (udpha->uha_checksum == 0) 7707c478bd9Sstevel@tonic-gate udpha->uha_checksum = 0xFFFF; 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate #undef DOWN_SUM 7737c478bd9Sstevel@tonic-gate break; 7747c478bd9Sstevel@tonic-gate case IPPROTO_IP: 7757c478bd9Sstevel@tonic-gate /* 7767c478bd9Sstevel@tonic-gate * This case is only an issue for self-encapsulated 7777c478bd9Sstevel@tonic-gate * packets. So for now, fall through. 7787c478bd9Sstevel@tonic-gate */ 7797c478bd9Sstevel@tonic-gate break; 7807c478bd9Sstevel@tonic-gate } 781bd670b35SErik Nordmark return (data_mp); 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate /* 78632350c00Sdanmcd * Strip ESP header, check padding, and fix IP header. 7877c478bd9Sstevel@tonic-gate * Returns B_TRUE on success, B_FALSE if an error occured. 7887c478bd9Sstevel@tonic-gate */ 7897c478bd9Sstevel@tonic-gate static boolean_t 7907c478bd9Sstevel@tonic-gate esp_strip_header(mblk_t *data_mp, boolean_t isv4, uint32_t ivlen, 791f4b3ec61Sdh155122 kstat_named_t **counter, ipsecesp_stack_t *espstack) 7927c478bd9Sstevel@tonic-gate { 7937c478bd9Sstevel@tonic-gate ipha_t *ipha; 7947c478bd9Sstevel@tonic-gate ip6_t *ip6h; 7957c478bd9Sstevel@tonic-gate uint_t divpoint; 7967c478bd9Sstevel@tonic-gate mblk_t *scratch; 7977c478bd9Sstevel@tonic-gate uint8_t nexthdr, padlen; 7987c478bd9Sstevel@tonic-gate uint8_t lastpad; 799f4b3ec61Sdh155122 ipsec_stack_t *ipss = espstack->ipsecesp_netstack->netstack_ipsec; 80032350c00Sdanmcd uint8_t *lastbyte; 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate /* 8037c478bd9Sstevel@tonic-gate * Strip ESP data and fix IP header. 8047c478bd9Sstevel@tonic-gate * 8057c478bd9Sstevel@tonic-gate * XXX In case the beginning of esp_inbound() changes to not do a 8067c478bd9Sstevel@tonic-gate * pullup, this part of the code can remain unchanged. 8077c478bd9Sstevel@tonic-gate */ 8087c478bd9Sstevel@tonic-gate if (isv4) { 8097c478bd9Sstevel@tonic-gate ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (ipha_t)); 8107c478bd9Sstevel@tonic-gate ipha = (ipha_t *)data_mp->b_rptr; 8117c478bd9Sstevel@tonic-gate ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (esph_t) + 8127c478bd9Sstevel@tonic-gate IPH_HDR_LENGTH(ipha)); 8137c478bd9Sstevel@tonic-gate divpoint = IPH_HDR_LENGTH(ipha); 8147c478bd9Sstevel@tonic-gate } else { 8157c478bd9Sstevel@tonic-gate ASSERT((data_mp->b_wptr - data_mp->b_rptr) >= sizeof (ip6_t)); 8167c478bd9Sstevel@tonic-gate ip6h = (ip6_t *)data_mp->b_rptr; 8177c478bd9Sstevel@tonic-gate divpoint = ip_hdr_length_v6(data_mp, ip6h); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate scratch = data_mp; 8217c478bd9Sstevel@tonic-gate while (scratch->b_cont != NULL) 8227c478bd9Sstevel@tonic-gate scratch = scratch->b_cont; 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate ASSERT((scratch->b_wptr - scratch->b_rptr) >= 3); 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate /* 8277c478bd9Sstevel@tonic-gate * "Next header" and padding length are the last two bytes in the 8287c478bd9Sstevel@tonic-gate * ESP-protected datagram, thus the explicit - 1 and - 2. 8297c478bd9Sstevel@tonic-gate * lastpad is the last byte of the padding, which can be used for 8307c478bd9Sstevel@tonic-gate * a quick check to see if the padding is correct. 8317c478bd9Sstevel@tonic-gate */ 83232350c00Sdanmcd lastbyte = scratch->b_wptr - 1; 83332350c00Sdanmcd nexthdr = *lastbyte--; 83432350c00Sdanmcd padlen = *lastbyte--; 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate if (isv4) { 8377c478bd9Sstevel@tonic-gate /* Fix part of the IP header. */ 8387c478bd9Sstevel@tonic-gate ipha->ipha_protocol = nexthdr; 8397c478bd9Sstevel@tonic-gate /* 8407c478bd9Sstevel@tonic-gate * Reality check the padlen. The explicit - 2 is for the 8417c478bd9Sstevel@tonic-gate * padding length and the next-header bytes. 8427c478bd9Sstevel@tonic-gate */ 8437c478bd9Sstevel@tonic-gate if (padlen >= ntohs(ipha->ipha_length) - sizeof (ipha_t) - 2 - 8447c478bd9Sstevel@tonic-gate sizeof (esph_t) - ivlen) { 845f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, bad_decrypt); 846f4b3ec61Sdh155122 ipsec_rl_strlog(espstack->ipsecesp_netstack, 847f4b3ec61Sdh155122 info.mi_idnum, 0, 0, 848f4b3ec61Sdh155122 SL_ERROR | SL_WARN, 84932350c00Sdanmcd "Corrupt ESP packet (padlen too big).\n"); 850f4b3ec61Sdh155122 esp1dbg(espstack, ("padlen (%d) is greater than:\n", 851f4b3ec61Sdh155122 padlen)); 852f4b3ec61Sdh155122 esp1dbg(espstack, ("pkt len(%d) - ip hdr - esp " 853f4b3ec61Sdh155122 "hdr - ivlen(%d) = %d.\n", 854f4b3ec61Sdh155122 ntohs(ipha->ipha_length), ivlen, 8557c478bd9Sstevel@tonic-gate (int)(ntohs(ipha->ipha_length) - sizeof (ipha_t) - 8567c478bd9Sstevel@tonic-gate 2 - sizeof (esph_t) - ivlen))); 857f4b3ec61Sdh155122 *counter = DROPPER(ipss, ipds_esp_bad_padlen); 8587c478bd9Sstevel@tonic-gate return (B_FALSE); 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate /* 8627c478bd9Sstevel@tonic-gate * Fix the rest of the header. The explicit - 2 is for the 8637c478bd9Sstevel@tonic-gate * padding length and the next-header bytes. 8647c478bd9Sstevel@tonic-gate */ 8657c478bd9Sstevel@tonic-gate ipha->ipha_length = htons(ntohs(ipha->ipha_length) - padlen - 8667c478bd9Sstevel@tonic-gate 2 - sizeof (esph_t) - ivlen); 8677c478bd9Sstevel@tonic-gate ipha->ipha_hdr_checksum = 0; 8687c478bd9Sstevel@tonic-gate ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha); 8697c478bd9Sstevel@tonic-gate } else { 8707c478bd9Sstevel@tonic-gate if (ip6h->ip6_nxt == IPPROTO_ESP) { 8717c478bd9Sstevel@tonic-gate ip6h->ip6_nxt = nexthdr; 8727c478bd9Sstevel@tonic-gate } else { 873bd670b35SErik Nordmark ip_pkt_t ipp; 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate bzero(&ipp, sizeof (ipp)); 876bd670b35SErik Nordmark (void) ip_find_hdr_v6(data_mp, ip6h, B_FALSE, &ipp, 877bd670b35SErik Nordmark NULL); 8787c478bd9Sstevel@tonic-gate if (ipp.ipp_dstopts != NULL) { 8797c478bd9Sstevel@tonic-gate ipp.ipp_dstopts->ip6d_nxt = nexthdr; 8807c478bd9Sstevel@tonic-gate } else if (ipp.ipp_rthdr != NULL) { 8817c478bd9Sstevel@tonic-gate ipp.ipp_rthdr->ip6r_nxt = nexthdr; 8827c478bd9Sstevel@tonic-gate } else if (ipp.ipp_hopopts != NULL) { 8837c478bd9Sstevel@tonic-gate ipp.ipp_hopopts->ip6h_nxt = nexthdr; 8847c478bd9Sstevel@tonic-gate } else { 8857c478bd9Sstevel@tonic-gate /* Panic a DEBUG kernel. */ 8867c478bd9Sstevel@tonic-gate ASSERT(ipp.ipp_hopopts != NULL); 8877c478bd9Sstevel@tonic-gate /* Otherwise, pretend it's IP + ESP. */ 8887c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "ESP IPv6 headers wrong.\n"); 8897c478bd9Sstevel@tonic-gate ip6h->ip6_nxt = nexthdr; 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate if (padlen >= ntohs(ip6h->ip6_plen) - 2 - sizeof (esph_t) - 8947c478bd9Sstevel@tonic-gate ivlen) { 895f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, bad_decrypt); 896f4b3ec61Sdh155122 ipsec_rl_strlog(espstack->ipsecesp_netstack, 897f4b3ec61Sdh155122 info.mi_idnum, 0, 0, 898f4b3ec61Sdh155122 SL_ERROR | SL_WARN, 89932350c00Sdanmcd "Corrupt ESP packet (v6 padlen too big).\n"); 900f4b3ec61Sdh155122 esp1dbg(espstack, ("padlen (%d) is greater than:\n", 901f4b3ec61Sdh155122 padlen)); 902437220cdSdanmcd esp1dbg(espstack, 903437220cdSdanmcd ("pkt len(%u) - ip hdr - esp hdr - ivlen(%d) = " 904437220cdSdanmcd "%u.\n", (unsigned)(ntohs(ip6h->ip6_plen) 9057c478bd9Sstevel@tonic-gate + sizeof (ip6_t)), ivlen, 9067c478bd9Sstevel@tonic-gate (unsigned)(ntohs(ip6h->ip6_plen) - 2 - 9077c478bd9Sstevel@tonic-gate sizeof (esph_t) - ivlen))); 908f4b3ec61Sdh155122 *counter = DROPPER(ipss, ipds_esp_bad_padlen); 9097c478bd9Sstevel@tonic-gate return (B_FALSE); 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate /* 9147c478bd9Sstevel@tonic-gate * Fix the rest of the header. The explicit - 2 is for the 9157c478bd9Sstevel@tonic-gate * padding length and the next-header bytes. IPv6 is nice, 9167c478bd9Sstevel@tonic-gate * because there's no hdr checksum! 9177c478bd9Sstevel@tonic-gate */ 9187c478bd9Sstevel@tonic-gate ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - padlen - 9197c478bd9Sstevel@tonic-gate 2 - sizeof (esph_t) - ivlen); 9207c478bd9Sstevel@tonic-gate } 9217c478bd9Sstevel@tonic-gate 922f4b3ec61Sdh155122 if (espstack->ipsecesp_padding_check > 0 && padlen > 0) { 92332350c00Sdanmcd /* 92432350c00Sdanmcd * Weak padding check: compare last-byte to length, they 92532350c00Sdanmcd * should be equal. 92632350c00Sdanmcd */ 92732350c00Sdanmcd lastpad = *lastbyte--; 92832350c00Sdanmcd 92932350c00Sdanmcd if (padlen != lastpad) { 930f4b3ec61Sdh155122 ipsec_rl_strlog(espstack->ipsecesp_netstack, 931f4b3ec61Sdh155122 info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 93232350c00Sdanmcd "Corrupt ESP packet (lastpad != padlen).\n"); 933f4b3ec61Sdh155122 esp1dbg(espstack, 934f4b3ec61Sdh155122 ("lastpad (%d) not equal to padlen (%d):\n", 9357c478bd9Sstevel@tonic-gate lastpad, padlen)); 936f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, bad_padding); 937f4b3ec61Sdh155122 *counter = DROPPER(ipss, ipds_esp_bad_padding); 9387c478bd9Sstevel@tonic-gate return (B_FALSE); 9397c478bd9Sstevel@tonic-gate } 9407c478bd9Sstevel@tonic-gate 94132350c00Sdanmcd /* 94232350c00Sdanmcd * Strong padding check: Check all pad bytes to see that 94332350c00Sdanmcd * they're ascending. Go backwards using a descending counter 94432350c00Sdanmcd * to verify. padlen == 1 is checked by previous block, so 94532350c00Sdanmcd * only bother if we've more than 1 byte of padding. 94632350c00Sdanmcd * Consequently, start the check one byte before the location 94732350c00Sdanmcd * of "lastpad". 94832350c00Sdanmcd */ 949f4b3ec61Sdh155122 if (espstack->ipsecesp_padding_check > 1) { 95032350c00Sdanmcd /* 95132350c00Sdanmcd * This assert may have to become an if and a pullup 95232350c00Sdanmcd * if we start accepting multi-dblk mblks. For now, 95332350c00Sdanmcd * though, any packet here will have been pulled up in 95432350c00Sdanmcd * esp_inbound. 95532350c00Sdanmcd */ 95632350c00Sdanmcd ASSERT(MBLKL(scratch) >= lastpad + 3); 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate /* 95932350c00Sdanmcd * Use "--lastpad" because we already checked the very 96032350c00Sdanmcd * last pad byte previously. 9617c478bd9Sstevel@tonic-gate */ 96232350c00Sdanmcd while (--lastpad != 0) { 96332350c00Sdanmcd if (lastpad != *lastbyte) { 964f4b3ec61Sdh155122 ipsec_rl_strlog( 965f4b3ec61Sdh155122 espstack->ipsecesp_netstack, 966f4b3ec61Sdh155122 info.mi_idnum, 0, 0, 96732350c00Sdanmcd SL_ERROR | SL_WARN, "Corrupt ESP " 96832350c00Sdanmcd "packet (bad padding).\n"); 969f4b3ec61Sdh155122 esp1dbg(espstack, 970f4b3ec61Sdh155122 ("padding not in correct" 9717c478bd9Sstevel@tonic-gate " format:\n")); 972f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, bad_padding); 973f4b3ec61Sdh155122 *counter = DROPPER(ipss, 974f4b3ec61Sdh155122 ipds_esp_bad_padding); 9757c478bd9Sstevel@tonic-gate return (B_FALSE); 9767c478bd9Sstevel@tonic-gate } 97732350c00Sdanmcd lastbyte--; 97832350c00Sdanmcd } 9797c478bd9Sstevel@tonic-gate } 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate /* Trim off the padding. */ 9837c478bd9Sstevel@tonic-gate ASSERT(data_mp->b_cont == NULL); 9847c478bd9Sstevel@tonic-gate data_mp->b_wptr -= (padlen + 2); 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate /* 9877c478bd9Sstevel@tonic-gate * Remove the ESP header. 9887c478bd9Sstevel@tonic-gate * 9897c478bd9Sstevel@tonic-gate * The above assertions about data_mp's size will make this work. 9907c478bd9Sstevel@tonic-gate * 9917c478bd9Sstevel@tonic-gate * XXX Question: If I send up and get back a contiguous mblk, 9927c478bd9Sstevel@tonic-gate * would it be quicker to bcopy over, or keep doing the dupb stuff? 9937c478bd9Sstevel@tonic-gate * I go with copying for now. 9947c478bd9Sstevel@tonic-gate */ 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate if (IS_P2ALIGNED(data_mp->b_rptr, sizeof (uint32_t)) && 9977c478bd9Sstevel@tonic-gate IS_P2ALIGNED(ivlen, sizeof (uint32_t))) { 9987c478bd9Sstevel@tonic-gate uint8_t *start = data_mp->b_rptr; 9997c478bd9Sstevel@tonic-gate uint32_t *src, *dst; 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate src = (uint32_t *)(start + divpoint); 10027c478bd9Sstevel@tonic-gate dst = (uint32_t *)(start + divpoint + sizeof (esph_t) + ivlen); 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate ASSERT(IS_P2ALIGNED(dst, sizeof (uint32_t)) && 10057c478bd9Sstevel@tonic-gate IS_P2ALIGNED(src, sizeof (uint32_t))); 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate do { 10087c478bd9Sstevel@tonic-gate src--; 10097c478bd9Sstevel@tonic-gate dst--; 10107c478bd9Sstevel@tonic-gate *dst = *src; 10117c478bd9Sstevel@tonic-gate } while (src != (uint32_t *)start); 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate data_mp->b_rptr = (uchar_t *)dst; 10147c478bd9Sstevel@tonic-gate } else { 10157c478bd9Sstevel@tonic-gate uint8_t *start = data_mp->b_rptr; 10167c478bd9Sstevel@tonic-gate uint8_t *src, *dst; 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate src = start + divpoint; 10197c478bd9Sstevel@tonic-gate dst = src + sizeof (esph_t) + ivlen; 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate do { 10227c478bd9Sstevel@tonic-gate src--; 10237c478bd9Sstevel@tonic-gate dst--; 10247c478bd9Sstevel@tonic-gate *dst = *src; 10257c478bd9Sstevel@tonic-gate } while (src != start); 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate data_mp->b_rptr = dst; 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate 1030f4b3ec61Sdh155122 esp2dbg(espstack, ("data_mp after inbound ESP adjustment:\n")); 1031f4b3ec61Sdh155122 esp2dbg(espstack, (dump_msg(data_mp))); 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate return (B_TRUE); 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate 10367c478bd9Sstevel@tonic-gate /* 10377c478bd9Sstevel@tonic-gate * Updating use times can be tricky business if the ipsa_haspeer flag is 10387c478bd9Sstevel@tonic-gate * set. This function is called once in an SA's lifetime. 10397c478bd9Sstevel@tonic-gate * 10407c478bd9Sstevel@tonic-gate * Caller has to REFRELE "assoc" which is passed in. This function has 10417c478bd9Sstevel@tonic-gate * to REFRELE any peer SA that is obtained. 10427c478bd9Sstevel@tonic-gate */ 10437c478bd9Sstevel@tonic-gate static void 10447c478bd9Sstevel@tonic-gate esp_set_usetime(ipsa_t *assoc, boolean_t inbound) 10457c478bd9Sstevel@tonic-gate { 10467c478bd9Sstevel@tonic-gate ipsa_t *inassoc, *outassoc; 10477c478bd9Sstevel@tonic-gate isaf_t *bucket; 10487c478bd9Sstevel@tonic-gate sadb_t *sp; 10497c478bd9Sstevel@tonic-gate int outhash; 10507c478bd9Sstevel@tonic-gate boolean_t isv6; 1051f4b3ec61Sdh155122 netstack_t *ns = assoc->ipsa_netstack; 1052f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate /* No peer? No problem! */ 10557c478bd9Sstevel@tonic-gate if (!assoc->ipsa_haspeer) { 10567c478bd9Sstevel@tonic-gate sadb_set_usetime(assoc); 10577c478bd9Sstevel@tonic-gate return; 10587c478bd9Sstevel@tonic-gate } 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate /* 10617c478bd9Sstevel@tonic-gate * Otherwise, we want to grab both the original assoc and its peer. 10627c478bd9Sstevel@tonic-gate * There might be a race for this, but if it's a real race, the times 10637c478bd9Sstevel@tonic-gate * will be out-of-synch by at most a second, and since our time 10647c478bd9Sstevel@tonic-gate * granularity is a second, this won't be a problem. 10657c478bd9Sstevel@tonic-gate * 10667c478bd9Sstevel@tonic-gate * If we need tight synchronization on the peer SA, then we need to 10677c478bd9Sstevel@tonic-gate * reconsider. 10687c478bd9Sstevel@tonic-gate */ 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate /* Use address length to select IPv6/IPv4 */ 10717c478bd9Sstevel@tonic-gate isv6 = (assoc->ipsa_addrfam == AF_INET6); 1072f4b3ec61Sdh155122 sp = isv6 ? &espstack->esp_sadb.s_v6 : &espstack->esp_sadb.s_v4; 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate if (inbound) { 10757c478bd9Sstevel@tonic-gate inassoc = assoc; 10767c478bd9Sstevel@tonic-gate if (isv6) { 1077fb87b5d2Ssommerfe outhash = OUTBOUND_HASH_V6(sp, *((in6_addr_t *) 10787c478bd9Sstevel@tonic-gate &inassoc->ipsa_dstaddr)); 10797c478bd9Sstevel@tonic-gate } else { 1080fb87b5d2Ssommerfe outhash = OUTBOUND_HASH_V4(sp, *((ipaddr_t *) 10817c478bd9Sstevel@tonic-gate &inassoc->ipsa_dstaddr)); 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate bucket = &sp->sdb_of[outhash]; 10847c478bd9Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 10857c478bd9Sstevel@tonic-gate outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi, 10867c478bd9Sstevel@tonic-gate inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr, 10877c478bd9Sstevel@tonic-gate inassoc->ipsa_addrfam); 10887c478bd9Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 10897c478bd9Sstevel@tonic-gate if (outassoc == NULL) { 10907c478bd9Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 10917c478bd9Sstevel@tonic-gate esp0dbg(("esp_set_usetime: " 10927c478bd9Sstevel@tonic-gate "can't find peer for inbound.\n")); 10937c478bd9Sstevel@tonic-gate sadb_set_usetime(inassoc); 10947c478bd9Sstevel@tonic-gate return; 10957c478bd9Sstevel@tonic-gate } 10967c478bd9Sstevel@tonic-gate } else { 10977c478bd9Sstevel@tonic-gate outassoc = assoc; 1098fb87b5d2Ssommerfe bucket = INBOUND_BUCKET(sp, outassoc->ipsa_spi); 10997c478bd9Sstevel@tonic-gate mutex_enter(&bucket->isaf_lock); 11007c478bd9Sstevel@tonic-gate inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi, 11017c478bd9Sstevel@tonic-gate outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr, 11027c478bd9Sstevel@tonic-gate outassoc->ipsa_addrfam); 11037c478bd9Sstevel@tonic-gate mutex_exit(&bucket->isaf_lock); 11047c478bd9Sstevel@tonic-gate if (inassoc == NULL) { 11057c478bd9Sstevel@tonic-gate /* Q: Do we wish to set haspeer == B_FALSE? */ 11067c478bd9Sstevel@tonic-gate esp0dbg(("esp_set_usetime: " 11077c478bd9Sstevel@tonic-gate "can't find peer for outbound.\n")); 11087c478bd9Sstevel@tonic-gate sadb_set_usetime(outassoc); 11097c478bd9Sstevel@tonic-gate return; 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate /* Update usetime on both. */ 11147c478bd9Sstevel@tonic-gate sadb_set_usetime(inassoc); 11157c478bd9Sstevel@tonic-gate sadb_set_usetime(outassoc); 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate /* 11187c478bd9Sstevel@tonic-gate * REFRELE any peer SA. 11197c478bd9Sstevel@tonic-gate * 11207c478bd9Sstevel@tonic-gate * Because of the multi-line macro nature of IPSA_REFRELE, keep 11217c478bd9Sstevel@tonic-gate * them in { }. 11227c478bd9Sstevel@tonic-gate */ 11237c478bd9Sstevel@tonic-gate if (inbound) { 11247c478bd9Sstevel@tonic-gate IPSA_REFRELE(outassoc); 11257c478bd9Sstevel@tonic-gate } else { 11267c478bd9Sstevel@tonic-gate IPSA_REFRELE(inassoc); 11277c478bd9Sstevel@tonic-gate } 11287c478bd9Sstevel@tonic-gate } 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate /* 11317c478bd9Sstevel@tonic-gate * Handle ESP inbound data for IPv4 and IPv6. 11327c478bd9Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 1133bd670b35SErik Nordmark * mblk chain data_mp. 11347c478bd9Sstevel@tonic-gate */ 1135bd670b35SErik Nordmark mblk_t * 1136bd670b35SErik Nordmark esp_inbound(mblk_t *data_mp, void *arg, ip_recv_attr_t *ira) 11377c478bd9Sstevel@tonic-gate { 11387c478bd9Sstevel@tonic-gate esph_t *esph = (esph_t *)arg; 1139bd670b35SErik Nordmark ipsa_t *ipsa = ira->ira_ipsec_esp_sa; 1140bd670b35SErik Nordmark netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack; 1141f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 1142f4b3ec61Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec; 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate /* 11457c478bd9Sstevel@tonic-gate * We may wish to check replay in-range-only here as an optimization. 11467c478bd9Sstevel@tonic-gate * Include the reality check of ipsa->ipsa_replay > 11477c478bd9Sstevel@tonic-gate * ipsa->ipsa_replay_wsize for times when it's the first N packets, 11487c478bd9Sstevel@tonic-gate * where N == ipsa->ipsa_replay_wsize. 11497c478bd9Sstevel@tonic-gate * 11507c478bd9Sstevel@tonic-gate * Another check that may come here later is the "collision" check. 11517c478bd9Sstevel@tonic-gate * If legitimate packets flow quickly enough, this won't be a problem, 11527c478bd9Sstevel@tonic-gate * but collisions may cause authentication algorithm crunching to 11537c478bd9Sstevel@tonic-gate * take place when it doesn't need to. 11547c478bd9Sstevel@tonic-gate */ 11557c478bd9Sstevel@tonic-gate if (!sadb_replay_peek(ipsa, esph->esph_replay)) { 1156f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, replay_early_failures); 1157f4b3ec61Sdh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 1158bd670b35SErik Nordmark ip_drop_packet(data_mp, B_TRUE, ira->ira_ill, 1159f4b3ec61Sdh155122 DROPPER(ipss, ipds_esp_early_replay), 1160f4b3ec61Sdh155122 &espstack->esp_dropper); 1161bd670b35SErik Nordmark BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards); 1162bd670b35SErik Nordmark return (NULL); 11637c478bd9Sstevel@tonic-gate } 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate /* 11667c478bd9Sstevel@tonic-gate * Adjust the IP header's payload length to reflect the removal 11677c478bd9Sstevel@tonic-gate * of the ICV. 11687c478bd9Sstevel@tonic-gate */ 1169bd670b35SErik Nordmark if (!(ira->ira_flags & IRAF_IS_IPV4)) { 11707c478bd9Sstevel@tonic-gate ip6_t *ip6h = (ip6_t *)data_mp->b_rptr; 11717c478bd9Sstevel@tonic-gate ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - 11727c478bd9Sstevel@tonic-gate ipsa->ipsa_mac_len); 11737c478bd9Sstevel@tonic-gate } else { 11747c478bd9Sstevel@tonic-gate ipha_t *ipha = (ipha_t *)data_mp->b_rptr; 11757c478bd9Sstevel@tonic-gate ipha->ipha_length = htons(ntohs(ipha->ipha_length) - 11767c478bd9Sstevel@tonic-gate ipsa->ipsa_mac_len); 11777c478bd9Sstevel@tonic-gate } 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate /* submit the request to the crypto framework */ 1180bd670b35SErik Nordmark return (esp_submit_req_inbound(data_mp, ira, ipsa, 11817c478bd9Sstevel@tonic-gate (uint8_t *)esph - data_mp->b_rptr)); 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate /* 11857c478bd9Sstevel@tonic-gate * Perform the really difficult work of inserting the proposed situation. 11867c478bd9Sstevel@tonic-gate * Called while holding the algorithm lock. 11877c478bd9Sstevel@tonic-gate */ 11887c478bd9Sstevel@tonic-gate static void 1189bd670b35SErik Nordmark esp_insert_prop(sadb_prop_t *prop, ipsacq_t *acqrec, uint_t combs, 1190bd670b35SErik Nordmark netstack_t *ns) 11917c478bd9Sstevel@tonic-gate { 11927c478bd9Sstevel@tonic-gate sadb_comb_t *comb = (sadb_comb_t *)(prop + 1); 11937c478bd9Sstevel@tonic-gate ipsec_action_t *ap; 11947c478bd9Sstevel@tonic-gate ipsec_prot_t *prot; 1195bd670b35SErik Nordmark ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 1196bd670b35SErik Nordmark ipsec_stack_t *ipss = ns->netstack_ipsec; 11977c478bd9Sstevel@tonic-gate 1198f4b3ec61Sdh155122 ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock)); 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate prop->sadb_prop_exttype = SADB_EXT_PROPOSAL; 12017c478bd9Sstevel@tonic-gate prop->sadb_prop_len = SADB_8TO64(sizeof (sadb_prop_t)); 12027c478bd9Sstevel@tonic-gate *(uint32_t *)(&prop->sadb_prop_replay) = 0; /* Quick zero-out! */ 12037c478bd9Sstevel@tonic-gate 1204f4b3ec61Sdh155122 prop->sadb_prop_replay = espstack->ipsecesp_replay_size; 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate /* 1207bd670b35SErik Nordmark * Based upon algorithm properties, and what-not, prioritize a 1208bd670b35SErik Nordmark * proposal, based on the ordering of the ESP algorithms in the 1209bd670b35SErik Nordmark * alternatives in the policy rule or socket that was placed 1210bd670b35SErik Nordmark * in the acquire record. 12117c478bd9Sstevel@tonic-gate * 12127c478bd9Sstevel@tonic-gate * For each action in policy list 12137c478bd9Sstevel@tonic-gate * Add combination. If I've hit limit, return. 12147c478bd9Sstevel@tonic-gate */ 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate for (ap = acqrec->ipsacq_act; ap != NULL; 12177c478bd9Sstevel@tonic-gate ap = ap->ipa_next) { 12187c478bd9Sstevel@tonic-gate ipsec_alginfo_t *ealg = NULL; 12197c478bd9Sstevel@tonic-gate ipsec_alginfo_t *aalg = NULL; 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate if (ap->ipa_act.ipa_type != IPSEC_POLICY_APPLY) 12227c478bd9Sstevel@tonic-gate continue; 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate prot = &ap->ipa_act.ipa_apply; 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate if (!(prot->ipp_use_esp)) 12277c478bd9Sstevel@tonic-gate continue; 12287c478bd9Sstevel@tonic-gate 12297c478bd9Sstevel@tonic-gate if (prot->ipp_esp_auth_alg != 0) { 1230f4b3ec61Sdh155122 aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH] 12317c478bd9Sstevel@tonic-gate [prot->ipp_esp_auth_alg]; 12327c478bd9Sstevel@tonic-gate if (aalg == NULL || !ALG_VALID(aalg)) 12337c478bd9Sstevel@tonic-gate continue; 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate ASSERT(prot->ipp_encr_alg > 0); 1237f4b3ec61Sdh155122 ealg = ipss->ipsec_alglists[IPSEC_ALG_ENCR] 1238f4b3ec61Sdh155122 [prot->ipp_encr_alg]; 12397c478bd9Sstevel@tonic-gate if (ealg == NULL || !ALG_VALID(ealg)) 12407c478bd9Sstevel@tonic-gate continue; 12417c478bd9Sstevel@tonic-gate 12427c478bd9Sstevel@tonic-gate comb->sadb_comb_flags = 0; 12437c478bd9Sstevel@tonic-gate comb->sadb_comb_reserved = 0; 12447c478bd9Sstevel@tonic-gate comb->sadb_comb_encrypt = ealg->alg_id; 12457845d282Sdanmcd comb->sadb_comb_encrypt_minbits = 12467845d282Sdanmcd MAX(prot->ipp_espe_minbits, ealg->alg_ef_minbits); 12477845d282Sdanmcd comb->sadb_comb_encrypt_maxbits = 12487845d282Sdanmcd MIN(prot->ipp_espe_maxbits, ealg->alg_ef_maxbits); 1249628b0c67SMark Fenwick 12507c478bd9Sstevel@tonic-gate if (aalg == NULL) { 12517c478bd9Sstevel@tonic-gate comb->sadb_comb_auth = 0; 12527c478bd9Sstevel@tonic-gate comb->sadb_comb_auth_minbits = 0; 12537c478bd9Sstevel@tonic-gate comb->sadb_comb_auth_maxbits = 0; 12547c478bd9Sstevel@tonic-gate } else { 12557c478bd9Sstevel@tonic-gate comb->sadb_comb_auth = aalg->alg_id; 12567845d282Sdanmcd comb->sadb_comb_auth_minbits = 12577845d282Sdanmcd MAX(prot->ipp_espa_minbits, aalg->alg_ef_minbits); 12587845d282Sdanmcd comb->sadb_comb_auth_maxbits = 12597845d282Sdanmcd MIN(prot->ipp_espa_maxbits, aalg->alg_ef_maxbits); 12607c478bd9Sstevel@tonic-gate } 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate /* 12637c478bd9Sstevel@tonic-gate * The following may be based on algorithm 12647c478bd9Sstevel@tonic-gate * properties, but in the meantime, we just pick 12657c478bd9Sstevel@tonic-gate * some good, sensible numbers. Key mgmt. can 12667c478bd9Sstevel@tonic-gate * (and perhaps should) be the place to finalize 12677c478bd9Sstevel@tonic-gate * such decisions. 12687c478bd9Sstevel@tonic-gate */ 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate /* 12717c478bd9Sstevel@tonic-gate * No limits on allocations, since we really don't 12727c478bd9Sstevel@tonic-gate * support that concept currently. 12737c478bd9Sstevel@tonic-gate */ 12747c478bd9Sstevel@tonic-gate comb->sadb_comb_soft_allocations = 0; 12757c478bd9Sstevel@tonic-gate comb->sadb_comb_hard_allocations = 0; 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate /* 12787c478bd9Sstevel@tonic-gate * These may want to come from policy rule.. 12797c478bd9Sstevel@tonic-gate */ 1280f4b3ec61Sdh155122 comb->sadb_comb_soft_bytes = 1281f4b3ec61Sdh155122 espstack->ipsecesp_default_soft_bytes; 1282f4b3ec61Sdh155122 comb->sadb_comb_hard_bytes = 1283f4b3ec61Sdh155122 espstack->ipsecesp_default_hard_bytes; 1284f4b3ec61Sdh155122 comb->sadb_comb_soft_addtime = 1285f4b3ec61Sdh155122 espstack->ipsecesp_default_soft_addtime; 1286f4b3ec61Sdh155122 comb->sadb_comb_hard_addtime = 1287f4b3ec61Sdh155122 espstack->ipsecesp_default_hard_addtime; 1288f4b3ec61Sdh155122 comb->sadb_comb_soft_usetime = 1289f4b3ec61Sdh155122 espstack->ipsecesp_default_soft_usetime; 1290f4b3ec61Sdh155122 comb->sadb_comb_hard_usetime = 1291f4b3ec61Sdh155122 espstack->ipsecesp_default_hard_usetime; 12927c478bd9Sstevel@tonic-gate 12937c478bd9Sstevel@tonic-gate prop->sadb_prop_len += SADB_8TO64(sizeof (*comb)); 12947c478bd9Sstevel@tonic-gate if (--combs == 0) 12957c478bd9Sstevel@tonic-gate break; /* out of space.. */ 12967c478bd9Sstevel@tonic-gate comb++; 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate } 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate /* 13017c478bd9Sstevel@tonic-gate * Prepare and actually send the SADB_ACQUIRE message to PF_KEY. 13027c478bd9Sstevel@tonic-gate */ 13037c478bd9Sstevel@tonic-gate static void 1304f4b3ec61Sdh155122 esp_send_acquire(ipsacq_t *acqrec, mblk_t *extended, netstack_t *ns) 13057c478bd9Sstevel@tonic-gate { 13068810c16bSdanmcd uint_t combs; 13077c478bd9Sstevel@tonic-gate sadb_msg_t *samsg; 13087c478bd9Sstevel@tonic-gate sadb_prop_t *prop; 13098810c16bSdanmcd mblk_t *pfkeymp, *msgmp; 1310f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 1311f4b3ec61Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec; 13127c478bd9Sstevel@tonic-gate 1313f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, acquire_requests); 13147c478bd9Sstevel@tonic-gate 13157ba9381bSpwernau if (espstack->esp_pfkey_q == NULL) { 13167ba9381bSpwernau mutex_exit(&acqrec->ipsacq_lock); 13178810c16bSdanmcd return; 13187ba9381bSpwernau } 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate /* Set up ACQUIRE. */ 1321f4b3ec61Sdh155122 pfkeymp = sadb_setup_acquire(acqrec, SADB_SATYPE_ESP, 1322f4b3ec61Sdh155122 ns->netstack_ipsec); 13238810c16bSdanmcd if (pfkeymp == NULL) { 13247c478bd9Sstevel@tonic-gate esp0dbg(("sadb_setup_acquire failed.\n")); 13257ba9381bSpwernau mutex_exit(&acqrec->ipsacq_lock); 13268810c16bSdanmcd return; 13277c478bd9Sstevel@tonic-gate } 1328f4b3ec61Sdh155122 ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock)); 1329f4b3ec61Sdh155122 combs = ipss->ipsec_nalgs[IPSEC_ALG_AUTH] * 1330f4b3ec61Sdh155122 ipss->ipsec_nalgs[IPSEC_ALG_ENCR]; 13318810c16bSdanmcd msgmp = pfkeymp->b_cont; 13328810c16bSdanmcd samsg = (sadb_msg_t *)(msgmp->b_rptr); 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate /* Insert proposal here. */ 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate prop = (sadb_prop_t *)(((uint64_t *)samsg) + samsg->sadb_msg_len); 1337bd670b35SErik Nordmark esp_insert_prop(prop, acqrec, combs, ns); 13387c478bd9Sstevel@tonic-gate samsg->sadb_msg_len += prop->sadb_prop_len; 13397c478bd9Sstevel@tonic-gate msgmp->b_wptr += SADB_64TO8(samsg->sadb_msg_len); 13407c478bd9Sstevel@tonic-gate 1341f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate /* 13447c478bd9Sstevel@tonic-gate * Must mutex_exit() before sending PF_KEY message up, in 13457c478bd9Sstevel@tonic-gate * order to avoid recursive mutex_enter() if there are no registered 13467c478bd9Sstevel@tonic-gate * listeners. 13477c478bd9Sstevel@tonic-gate * 13487c478bd9Sstevel@tonic-gate * Once I've sent the message, I'm cool anyway. 13497c478bd9Sstevel@tonic-gate */ 13507c478bd9Sstevel@tonic-gate mutex_exit(&acqrec->ipsacq_lock); 13517c478bd9Sstevel@tonic-gate if (extended != NULL) { 1352f4b3ec61Sdh155122 putnext(espstack->esp_pfkey_q, extended); 13537c478bd9Sstevel@tonic-gate } 1354f4b3ec61Sdh155122 putnext(espstack->esp_pfkey_q, pfkeymp); 13557c478bd9Sstevel@tonic-gate } 13567c478bd9Sstevel@tonic-gate 13575d3b8cb7SBill Sommerfeld /* XXX refactor me */ 13587c478bd9Sstevel@tonic-gate /* 13597c478bd9Sstevel@tonic-gate * Handle the SADB_GETSPI message. Create a larval SA. 13607c478bd9Sstevel@tonic-gate */ 13617c478bd9Sstevel@tonic-gate static void 1362f4b3ec61Sdh155122 esp_getspi(mblk_t *mp, keysock_in_t *ksi, ipsecesp_stack_t *espstack) 13637c478bd9Sstevel@tonic-gate { 13647c478bd9Sstevel@tonic-gate ipsa_t *newbie, *target; 13657c478bd9Sstevel@tonic-gate isaf_t *outbound, *inbound; 13667c478bd9Sstevel@tonic-gate int rc, diagnostic; 13677c478bd9Sstevel@tonic-gate sadb_sa_t *assoc; 13687c478bd9Sstevel@tonic-gate keysock_out_t *kso; 13697c478bd9Sstevel@tonic-gate uint32_t newspi; 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate /* 13727c478bd9Sstevel@tonic-gate * Randomly generate a proposed SPI value 13737c478bd9Sstevel@tonic-gate */ 13749c2c14abSThejaswini Singarajipura if (cl_inet_getspi != NULL) { 13758e4b770fSLu Huafeng cl_inet_getspi(espstack->ipsecesp_netstack->netstack_stackid, 13768e4b770fSLu Huafeng IPPROTO_ESP, (uint8_t *)&newspi, sizeof (uint32_t), NULL); 13779c2c14abSThejaswini Singarajipura } else { 13789c2c14abSThejaswini Singarajipura (void) random_get_pseudo_bytes((uint8_t *)&newspi, 13799c2c14abSThejaswini Singarajipura sizeof (uint32_t)); 13809c2c14abSThejaswini Singarajipura } 1381f4b3ec61Sdh155122 newbie = sadb_getspi(ksi, newspi, &diagnostic, 13829c2c14abSThejaswini Singarajipura espstack->ipsecesp_netstack, IPPROTO_ESP); 13837c478bd9Sstevel@tonic-gate 13847c478bd9Sstevel@tonic-gate if (newbie == NULL) { 1385f4b3ec61Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, ENOMEM, diagnostic, 13867c478bd9Sstevel@tonic-gate ksi->ks_in_serial); 13877c478bd9Sstevel@tonic-gate return; 13887c478bd9Sstevel@tonic-gate } else if (newbie == (ipsa_t *)-1) { 1389f4b3ec61Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, EINVAL, diagnostic, 13907c478bd9Sstevel@tonic-gate ksi->ks_in_serial); 13917c478bd9Sstevel@tonic-gate return; 13927c478bd9Sstevel@tonic-gate } 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate /* 13957c478bd9Sstevel@tonic-gate * XXX - We may randomly collide. We really should recover from this. 13967c478bd9Sstevel@tonic-gate * Unfortunately, that could require spending way-too-much-time 13977c478bd9Sstevel@tonic-gate * in here. For now, let the user retry. 13987c478bd9Sstevel@tonic-gate */ 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate if (newbie->ipsa_addrfam == AF_INET6) { 1401f4b3ec61Sdh155122 outbound = OUTBOUND_BUCKET_V6(&espstack->esp_sadb.s_v6, 1402fb87b5d2Ssommerfe *(uint32_t *)(newbie->ipsa_dstaddr)); 1403f4b3ec61Sdh155122 inbound = INBOUND_BUCKET(&espstack->esp_sadb.s_v6, 1404f4b3ec61Sdh155122 newbie->ipsa_spi); 14057c478bd9Sstevel@tonic-gate } else { 14067c478bd9Sstevel@tonic-gate ASSERT(newbie->ipsa_addrfam == AF_INET); 1407f4b3ec61Sdh155122 outbound = OUTBOUND_BUCKET_V4(&espstack->esp_sadb.s_v4, 1408fb87b5d2Ssommerfe *(uint32_t *)(newbie->ipsa_dstaddr)); 1409f4b3ec61Sdh155122 inbound = INBOUND_BUCKET(&espstack->esp_sadb.s_v4, 1410f4b3ec61Sdh155122 newbie->ipsa_spi); 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate mutex_enter(&outbound->isaf_lock); 14147c478bd9Sstevel@tonic-gate mutex_enter(&inbound->isaf_lock); 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate /* 14177c478bd9Sstevel@tonic-gate * Check for collisions (i.e. did sadb_getspi() return with something 14187c478bd9Sstevel@tonic-gate * that already exists?). 14197c478bd9Sstevel@tonic-gate * 14207c478bd9Sstevel@tonic-gate * Try outbound first. Even though SADB_GETSPI is traditionally 14217c478bd9Sstevel@tonic-gate * for inbound SAs, you never know what a user might do. 14227c478bd9Sstevel@tonic-gate */ 14237c478bd9Sstevel@tonic-gate target = ipsec_getassocbyspi(outbound, newbie->ipsa_spi, 14247c478bd9Sstevel@tonic-gate newbie->ipsa_srcaddr, newbie->ipsa_dstaddr, newbie->ipsa_addrfam); 14257c478bd9Sstevel@tonic-gate if (target == NULL) { 14267c478bd9Sstevel@tonic-gate target = ipsec_getassocbyspi(inbound, newbie->ipsa_spi, 14277c478bd9Sstevel@tonic-gate newbie->ipsa_srcaddr, newbie->ipsa_dstaddr, 14287c478bd9Sstevel@tonic-gate newbie->ipsa_addrfam); 14297c478bd9Sstevel@tonic-gate } 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate /* 14327c478bd9Sstevel@tonic-gate * I don't have collisions elsewhere! 14337c478bd9Sstevel@tonic-gate * (Nor will I because I'm still holding inbound/outbound locks.) 14347c478bd9Sstevel@tonic-gate */ 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate if (target != NULL) { 14377c478bd9Sstevel@tonic-gate rc = EEXIST; 14387c478bd9Sstevel@tonic-gate IPSA_REFRELE(target); 14397c478bd9Sstevel@tonic-gate } else { 14407c478bd9Sstevel@tonic-gate /* 14417c478bd9Sstevel@tonic-gate * sadb_insertassoc() also checks for collisions, so 14427c478bd9Sstevel@tonic-gate * if there's a colliding entry, rc will be set 14437c478bd9Sstevel@tonic-gate * to EEXIST. 14447c478bd9Sstevel@tonic-gate */ 14457c478bd9Sstevel@tonic-gate rc = sadb_insertassoc(newbie, inbound); 1446437220cdSdanmcd newbie->ipsa_hardexpiretime = gethrestime_sec(); 1447f4b3ec61Sdh155122 newbie->ipsa_hardexpiretime += 1448f4b3ec61Sdh155122 espstack->ipsecesp_larval_timeout; 14497c478bd9Sstevel@tonic-gate } 14507c478bd9Sstevel@tonic-gate 14517c478bd9Sstevel@tonic-gate /* 14527c478bd9Sstevel@tonic-gate * Can exit outbound mutex. Hold inbound until we're done 14537c478bd9Sstevel@tonic-gate * with newbie. 14547c478bd9Sstevel@tonic-gate */ 14557c478bd9Sstevel@tonic-gate mutex_exit(&outbound->isaf_lock); 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate if (rc != 0) { 14587c478bd9Sstevel@tonic-gate mutex_exit(&inbound->isaf_lock); 14597c478bd9Sstevel@tonic-gate IPSA_REFRELE(newbie); 1460f4b3ec61Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, rc, 1461f4b3ec61Sdh155122 SADB_X_DIAGNOSTIC_NONE, ksi->ks_in_serial); 14627c478bd9Sstevel@tonic-gate return; 14637c478bd9Sstevel@tonic-gate } 14647c478bd9Sstevel@tonic-gate 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate /* Can write here because I'm still holding the bucket lock. */ 14677c478bd9Sstevel@tonic-gate newbie->ipsa_type = SADB_SATYPE_ESP; 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate /* 14707c478bd9Sstevel@tonic-gate * Construct successful return message. We have one thing going 14717c478bd9Sstevel@tonic-gate * for us in PF_KEY v2. That's the fact that 14727c478bd9Sstevel@tonic-gate * sizeof (sadb_spirange_t) == sizeof (sadb_sa_t) 14737c478bd9Sstevel@tonic-gate */ 14747c478bd9Sstevel@tonic-gate assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SPIRANGE]; 14757c478bd9Sstevel@tonic-gate assoc->sadb_sa_exttype = SADB_EXT_SA; 14767c478bd9Sstevel@tonic-gate assoc->sadb_sa_spi = newbie->ipsa_spi; 14777c478bd9Sstevel@tonic-gate *((uint64_t *)(&assoc->sadb_sa_replay)) = 0; 14787c478bd9Sstevel@tonic-gate mutex_exit(&inbound->isaf_lock); 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate /* Convert KEYSOCK_IN to KEYSOCK_OUT. */ 14817c478bd9Sstevel@tonic-gate kso = (keysock_out_t *)ksi; 14827c478bd9Sstevel@tonic-gate kso->ks_out_len = sizeof (*kso); 14837c478bd9Sstevel@tonic-gate kso->ks_out_serial = ksi->ks_in_serial; 14847c478bd9Sstevel@tonic-gate kso->ks_out_type = KEYSOCK_OUT; 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate /* 14877c478bd9Sstevel@tonic-gate * Can safely putnext() to esp_pfkey_q, because this is a turnaround 14887c478bd9Sstevel@tonic-gate * from the esp_pfkey_q. 14897c478bd9Sstevel@tonic-gate */ 1490f4b3ec61Sdh155122 putnext(espstack->esp_pfkey_q, mp); 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate /* 14947c478bd9Sstevel@tonic-gate * Insert the ESP header into a packet. Duplicate an mblk, and insert a newly 14957c478bd9Sstevel@tonic-gate * allocated mblk with the ESP header in between the two. 14967c478bd9Sstevel@tonic-gate */ 14977c478bd9Sstevel@tonic-gate static boolean_t 1498f4b3ec61Sdh155122 esp_insert_esp(mblk_t *mp, mblk_t *esp_mp, uint_t divpoint, 1499f4b3ec61Sdh155122 ipsecesp_stack_t *espstack) 15007c478bd9Sstevel@tonic-gate { 15017c478bd9Sstevel@tonic-gate mblk_t *split_mp = mp; 15027c478bd9Sstevel@tonic-gate uint_t wheretodiv = divpoint; 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate while ((split_mp->b_wptr - split_mp->b_rptr) < wheretodiv) { 15057c478bd9Sstevel@tonic-gate wheretodiv -= (split_mp->b_wptr - split_mp->b_rptr); 15067c478bd9Sstevel@tonic-gate split_mp = split_mp->b_cont; 15077c478bd9Sstevel@tonic-gate ASSERT(split_mp != NULL); 15087c478bd9Sstevel@tonic-gate } 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate if (split_mp->b_wptr - split_mp->b_rptr != wheretodiv) { 15117c478bd9Sstevel@tonic-gate mblk_t *scratch; 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate /* "scratch" is the 2nd half, split_mp is the first. */ 15147c478bd9Sstevel@tonic-gate scratch = dupb(split_mp); 15157c478bd9Sstevel@tonic-gate if (scratch == NULL) { 1516f4b3ec61Sdh155122 esp1dbg(espstack, 1517f4b3ec61Sdh155122 ("esp_insert_esp: can't allocate scratch.\n")); 15187c478bd9Sstevel@tonic-gate return (B_FALSE); 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate /* NOTE: dupb() doesn't set b_cont appropriately. */ 15217c478bd9Sstevel@tonic-gate scratch->b_cont = split_mp->b_cont; 15227c478bd9Sstevel@tonic-gate scratch->b_rptr += wheretodiv; 15237c478bd9Sstevel@tonic-gate split_mp->b_wptr = split_mp->b_rptr + wheretodiv; 15247c478bd9Sstevel@tonic-gate split_mp->b_cont = scratch; 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate /* 15277c478bd9Sstevel@tonic-gate * At this point, split_mp is exactly "wheretodiv" bytes long, and 15287c478bd9Sstevel@tonic-gate * holds the end of the pre-ESP part of the datagram. 15297c478bd9Sstevel@tonic-gate */ 15307c478bd9Sstevel@tonic-gate esp_mp->b_cont = split_mp->b_cont; 15317c478bd9Sstevel@tonic-gate split_mp->b_cont = esp_mp; 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate return (B_TRUE); 15347c478bd9Sstevel@tonic-gate } 15357c478bd9Sstevel@tonic-gate 15367c478bd9Sstevel@tonic-gate /* 15374a179720Sdanmcd * Section 7 of RFC 3947 says: 15384a179720Sdanmcd * 15394a179720Sdanmcd * 7. Recovering from the Expiring NAT Mappings 15404a179720Sdanmcd * 15414a179720Sdanmcd * There are cases where NAT box decides to remove mappings that are still 15424a179720Sdanmcd * alive (for example, when the keepalive interval is too long, or when the 15434a179720Sdanmcd * NAT box is rebooted). To recover from this, ends that are NOT behind 15444a179720Sdanmcd * NAT SHOULD use the last valid UDP encapsulated IKE or IPsec packet from 15454a179720Sdanmcd * the other end to determine which IP and port addresses should be used. 15464a179720Sdanmcd * The host behind dynamic NAT MUST NOT do this, as otherwise it opens a 15474a179720Sdanmcd * DoS attack possibility because the IP address or port of the other host 15484a179720Sdanmcd * will not change (it is not behind NAT). 15494a179720Sdanmcd * 15504a179720Sdanmcd * Keepalives cannot be used for these purposes, as they are not 15514a179720Sdanmcd * authenticated, but any IKE authenticated IKE packet or ESP packet can be 15524a179720Sdanmcd * used to detect whether the IP address or the port has changed. 15534a179720Sdanmcd * 15544a179720Sdanmcd * The following function will check an SA and its explicitly-set pair to see 15554a179720Sdanmcd * if the NAT-T remote port matches the received packet (which must have 15564a179720Sdanmcd * passed ESP authentication, see esp_in_done() for the caller context). If 15574a179720Sdanmcd * there is a mismatch, the SAs are updated. It is not important if we race 15584a179720Sdanmcd * with a transmitting thread, as if there is a transmitting thread, it will 15594a179720Sdanmcd * merely emit a packet that will most-likely be dropped. 15604a179720Sdanmcd * 15614a179720Sdanmcd * "ports" are ordered src,dst, and assoc is an inbound SA, where src should 15624a179720Sdanmcd * match ipsa_remote_nat_port and dst should match ipsa_local_nat_port. 15634a179720Sdanmcd */ 15644a179720Sdanmcd #ifdef _LITTLE_ENDIAN 15654a179720Sdanmcd #define FIRST_16(x) ((x) & 0xFFFF) 15664a179720Sdanmcd #define NEXT_16(x) (((x) >> 16) & 0xFFFF) 15674a179720Sdanmcd #else 15684a179720Sdanmcd #define FIRST_16(x) (((x) >> 16) & 0xFFFF) 15694a179720Sdanmcd #define NEXT_16(x) ((x) & 0xFFFF) 15704a179720Sdanmcd #endif 15714a179720Sdanmcd static void 15724a179720Sdanmcd esp_port_freshness(uint32_t ports, ipsa_t *assoc) 15734a179720Sdanmcd { 15744a179720Sdanmcd uint16_t remote = FIRST_16(ports); 15754a179720Sdanmcd uint16_t local = NEXT_16(ports); 15764a179720Sdanmcd ipsa_t *outbound_peer; 15774a179720Sdanmcd isaf_t *bucket; 15784a179720Sdanmcd ipsecesp_stack_t *espstack = assoc->ipsa_netstack->netstack_ipsecesp; 15794a179720Sdanmcd 15804a179720Sdanmcd /* We found a conn_t, therefore local != 0. */ 15814a179720Sdanmcd ASSERT(local != 0); 15824a179720Sdanmcd /* Assume an IPv4 SA. */ 15834a179720Sdanmcd ASSERT(assoc->ipsa_addrfam == AF_INET); 15844a179720Sdanmcd 15854a179720Sdanmcd /* 15864a179720Sdanmcd * On-the-wire rport == 0 means something's very wrong. 15874a179720Sdanmcd * An unpaired SA is also useless to us. 15884a179720Sdanmcd * If we are behind the NAT, don't bother. 15894a179720Sdanmcd * A zero local NAT port defaults to 4500, so check that too. 15904a179720Sdanmcd * And, of course, if the ports already match, we don't need to 15914a179720Sdanmcd * bother. 15924a179720Sdanmcd */ 15934a179720Sdanmcd if (remote == 0 || assoc->ipsa_otherspi == 0 || 15944a179720Sdanmcd (assoc->ipsa_flags & IPSA_F_BEHIND_NAT) || 15954a179720Sdanmcd (assoc->ipsa_remote_nat_port == 0 && 15964a179720Sdanmcd remote == htons(IPPORT_IKE_NATT)) || 15974a179720Sdanmcd remote == assoc->ipsa_remote_nat_port) 15984a179720Sdanmcd return; 15994a179720Sdanmcd 16004a179720Sdanmcd /* Try and snag the peer. NOTE: Assume IPv4 for now. */ 16014a179720Sdanmcd bucket = OUTBOUND_BUCKET_V4(&(espstack->esp_sadb.s_v4), 16024a179720Sdanmcd assoc->ipsa_srcaddr[0]); 16034a179720Sdanmcd mutex_enter(&bucket->isaf_lock); 16044a179720Sdanmcd outbound_peer = ipsec_getassocbyspi(bucket, assoc->ipsa_otherspi, 16054a179720Sdanmcd assoc->ipsa_dstaddr, assoc->ipsa_srcaddr, AF_INET); 16064a179720Sdanmcd mutex_exit(&bucket->isaf_lock); 16074a179720Sdanmcd 16084a179720Sdanmcd /* We probably lost a race to a deleting or expiring thread. */ 16094a179720Sdanmcd if (outbound_peer == NULL) 16104a179720Sdanmcd return; 16114a179720Sdanmcd 16124a179720Sdanmcd /* 16134a179720Sdanmcd * Hold the mutexes for both SAs so we don't race another inbound 16144a179720Sdanmcd * thread. A lock-entry order shouldn't matter, since all other 16154a179720Sdanmcd * per-ipsa locks are individually held-then-released. 16164a179720Sdanmcd * 16174a179720Sdanmcd * Luckily, this has nothing to do with the remote-NAT address, 16184a179720Sdanmcd * so we don't have to re-scribble the cached-checksum differential. 16194a179720Sdanmcd */ 16204a179720Sdanmcd mutex_enter(&outbound_peer->ipsa_lock); 16214a179720Sdanmcd mutex_enter(&assoc->ipsa_lock); 16224a179720Sdanmcd outbound_peer->ipsa_remote_nat_port = assoc->ipsa_remote_nat_port = 16234a179720Sdanmcd remote; 16244a179720Sdanmcd mutex_exit(&assoc->ipsa_lock); 16254a179720Sdanmcd mutex_exit(&outbound_peer->ipsa_lock); 16264a179720Sdanmcd IPSA_REFRELE(outbound_peer); 16274a179720Sdanmcd ESP_BUMP_STAT(espstack, sa_port_renumbers); 16284a179720Sdanmcd } 16294a179720Sdanmcd /* 16307c478bd9Sstevel@tonic-gate * Finish processing of an inbound ESP packet after processing by the 16317c478bd9Sstevel@tonic-gate * crypto framework. 16327c478bd9Sstevel@tonic-gate * - Remove the ESP header. 16337c478bd9Sstevel@tonic-gate * - Send packet back to IP. 16347c478bd9Sstevel@tonic-gate * If authentication was performed on the packet, this function is called 16357c478bd9Sstevel@tonic-gate * only if the authentication succeeded. 16367c478bd9Sstevel@tonic-gate * On success returns B_TRUE, on failure returns B_FALSE and frees the 1637bd670b35SErik Nordmark * mblk chain data_mp. 16387c478bd9Sstevel@tonic-gate */ 1639bd670b35SErik Nordmark static mblk_t * 1640bd670b35SErik Nordmark esp_in_done(mblk_t *data_mp, ip_recv_attr_t *ira, ipsec_crypto_t *ic) 16417c478bd9Sstevel@tonic-gate { 16427c478bd9Sstevel@tonic-gate ipsa_t *assoc; 16437c478bd9Sstevel@tonic-gate uint_t espstart; 16447c478bd9Sstevel@tonic-gate uint32_t ivlen = 0; 16457c478bd9Sstevel@tonic-gate uint_t processed_len; 16467c478bd9Sstevel@tonic-gate esph_t *esph; 16477c478bd9Sstevel@tonic-gate kstat_named_t *counter; 16487c478bd9Sstevel@tonic-gate boolean_t is_natt; 1649bd670b35SErik Nordmark netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack; 1650f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 1651f4b3ec61Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec; 16527c478bd9Sstevel@tonic-gate 1653bd670b35SErik Nordmark assoc = ira->ira_ipsec_esp_sa; 16547c478bd9Sstevel@tonic-gate ASSERT(assoc != NULL); 16557c478bd9Sstevel@tonic-gate 16567c478bd9Sstevel@tonic-gate is_natt = ((assoc->ipsa_flags & IPSA_F_NATT) != 0); 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate /* get the pointer to the ESP header */ 16597c478bd9Sstevel@tonic-gate if (assoc->ipsa_encr_alg == SADB_EALG_NULL) { 16607c478bd9Sstevel@tonic-gate /* authentication-only ESP */ 1661bd670b35SErik Nordmark espstart = ic->ic_crypto_data.cd_offset; 1662bd670b35SErik Nordmark processed_len = ic->ic_crypto_data.cd_length; 16637c478bd9Sstevel@tonic-gate } else { 16647c478bd9Sstevel@tonic-gate /* encryption present */ 16657c478bd9Sstevel@tonic-gate ivlen = assoc->ipsa_iv_len; 16667c478bd9Sstevel@tonic-gate if (assoc->ipsa_auth_alg == SADB_AALG_NONE) { 16677c478bd9Sstevel@tonic-gate /* encryption-only ESP */ 1668bd670b35SErik Nordmark espstart = ic->ic_crypto_data.cd_offset - 16697c478bd9Sstevel@tonic-gate sizeof (esph_t) - assoc->ipsa_iv_len; 1670bd670b35SErik Nordmark processed_len = ic->ic_crypto_data.cd_length + 16717c478bd9Sstevel@tonic-gate ivlen; 16727c478bd9Sstevel@tonic-gate } else { 16737c478bd9Sstevel@tonic-gate /* encryption with authentication */ 1674bd670b35SErik Nordmark espstart = ic->ic_crypto_dual_data.dd_offset1; 1675bd670b35SErik Nordmark processed_len = ic->ic_crypto_dual_data.dd_len2 + 16767c478bd9Sstevel@tonic-gate ivlen; 16777c478bd9Sstevel@tonic-gate } 16787c478bd9Sstevel@tonic-gate } 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate esph = (esph_t *)(data_mp->b_rptr + espstart); 16817c478bd9Sstevel@tonic-gate 1682628b0c67SMark Fenwick if (assoc->ipsa_auth_alg != IPSA_AALG_NONE || 1683628b0c67SMark Fenwick (assoc->ipsa_flags & IPSA_F_COMBINED)) { 1684628b0c67SMark Fenwick /* 1685628b0c67SMark Fenwick * Authentication passed if we reach this point. 1686628b0c67SMark Fenwick * Packets with authentication will have the ICV 1687628b0c67SMark Fenwick * after the crypto data. Adjust b_wptr before 1688628b0c67SMark Fenwick * making padlen checks. 1689628b0c67SMark Fenwick */ 1690f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, good_auth); 16917c478bd9Sstevel@tonic-gate data_mp->b_wptr -= assoc->ipsa_mac_len; 16927c478bd9Sstevel@tonic-gate 16937c478bd9Sstevel@tonic-gate /* 16947c478bd9Sstevel@tonic-gate * Check replay window here! 16957c478bd9Sstevel@tonic-gate * For right now, assume keysock will set the replay window 16967c478bd9Sstevel@tonic-gate * size to zero for SAs that have an unspecified sender. 16977c478bd9Sstevel@tonic-gate * This may change... 16987c478bd9Sstevel@tonic-gate */ 16997c478bd9Sstevel@tonic-gate 17007c478bd9Sstevel@tonic-gate if (!sadb_replay_check(assoc, esph->esph_replay)) { 17017c478bd9Sstevel@tonic-gate /* 17027c478bd9Sstevel@tonic-gate * Log the event. As of now we print out an event. 17037c478bd9Sstevel@tonic-gate * Do not print the replay failure number, or else 17047c478bd9Sstevel@tonic-gate * syslog cannot collate the error messages. Printing 17057c478bd9Sstevel@tonic-gate * the replay number that failed opens a denial-of- 17067c478bd9Sstevel@tonic-gate * service attack. 17077c478bd9Sstevel@tonic-gate */ 17087c478bd9Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, 17097c478bd9Sstevel@tonic-gate SL_ERROR | SL_WARN, 17107c478bd9Sstevel@tonic-gate "Replay failed for ESP spi 0x%x, dst %s.\n", 17117c478bd9Sstevel@tonic-gate assoc->ipsa_spi, assoc->ipsa_dstaddr, 1712f4b3ec61Sdh155122 assoc->ipsa_addrfam, espstack->ipsecesp_netstack); 1713f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, replay_failures); 1714f4b3ec61Sdh155122 counter = DROPPER(ipss, ipds_esp_replay); 17157c478bd9Sstevel@tonic-gate goto drop_and_bail; 17167c478bd9Sstevel@tonic-gate } 17174a179720Sdanmcd 1718bd670b35SErik Nordmark if (is_natt) { 1719bd670b35SErik Nordmark ASSERT(ira->ira_flags & IRAF_ESP_UDP_PORTS); 1720bd670b35SErik Nordmark ASSERT(ira->ira_esp_udp_ports != 0); 1721bd670b35SErik Nordmark esp_port_freshness(ira->ira_esp_udp_ports, assoc); 1722bd670b35SErik Nordmark } 17237c478bd9Sstevel@tonic-gate } 17247c478bd9Sstevel@tonic-gate 1725437220cdSdanmcd esp_set_usetime(assoc, B_TRUE); 1726437220cdSdanmcd 17277c478bd9Sstevel@tonic-gate if (!esp_age_bytes(assoc, processed_len, B_TRUE)) { 17287c478bd9Sstevel@tonic-gate /* The ipsa has hit hard expiration, LOG and AUDIT. */ 17297c478bd9Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, 17307c478bd9Sstevel@tonic-gate SL_ERROR | SL_WARN, 17317c478bd9Sstevel@tonic-gate "ESP association 0x%x, dst %s had bytes expire.\n", 1732f4b3ec61Sdh155122 assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam, 1733f4b3ec61Sdh155122 espstack->ipsecesp_netstack); 1734f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, bytes_expired); 1735f4b3ec61Sdh155122 counter = DROPPER(ipss, ipds_esp_bytes_expire); 17367c478bd9Sstevel@tonic-gate goto drop_and_bail; 17377c478bd9Sstevel@tonic-gate } 17387c478bd9Sstevel@tonic-gate 17397c478bd9Sstevel@tonic-gate /* 17407c478bd9Sstevel@tonic-gate * Remove ESP header and padding from packet. I hope the compiler 17417c478bd9Sstevel@tonic-gate * spews "branch, predict taken" code for this. 17427c478bd9Sstevel@tonic-gate */ 17437c478bd9Sstevel@tonic-gate 1744bd670b35SErik Nordmark if (esp_strip_header(data_mp, (ira->ira_flags & IRAF_IS_IPV4), 1745bd670b35SErik Nordmark ivlen, &counter, espstack)) { 17465d3b8cb7SBill Sommerfeld 1747bd670b35SErik Nordmark if (is_system_labeled() && assoc->ipsa_tsl != NULL) { 1748bd670b35SErik Nordmark if (!ip_recv_attr_replace_label(ira, assoc->ipsa_tsl)) { 1749bd670b35SErik Nordmark ip_drop_packet(data_mp, B_TRUE, ira->ira_ill, 1750bd670b35SErik Nordmark DROPPER(ipss, ipds_ah_nomem), 1751bd670b35SErik Nordmark &espstack->esp_dropper); 1752bd670b35SErik Nordmark BUMP_MIB(ira->ira_ill->ill_ip_mib, 1753bd670b35SErik Nordmark ipIfStatsInDiscards); 1754bd670b35SErik Nordmark return (NULL); 17555d3b8cb7SBill Sommerfeld } 17565d3b8cb7SBill Sommerfeld } 17577c478bd9Sstevel@tonic-gate if (is_natt) 17587c478bd9Sstevel@tonic-gate return (esp_fix_natt_checksums(data_mp, assoc)); 1759d74f5ecaSDan McDonald 1760d74f5ecaSDan McDonald if (assoc->ipsa_state == IPSA_STATE_IDLE) { 1761d74f5ecaSDan McDonald /* 1762d74f5ecaSDan McDonald * Cluster buffering case. Tell caller that we're 1763d74f5ecaSDan McDonald * handling the packet. 1764d74f5ecaSDan McDonald */ 1765bd670b35SErik Nordmark sadb_buf_pkt(assoc, data_mp, ira); 1766bd670b35SErik Nordmark return (NULL); 1767d74f5ecaSDan McDonald } 1768d74f5ecaSDan McDonald 1769bd670b35SErik Nordmark return (data_mp); 17707c478bd9Sstevel@tonic-gate } 17717c478bd9Sstevel@tonic-gate 1772f4b3ec61Sdh155122 esp1dbg(espstack, ("esp_in_done: esp_strip_header() failed\n")); 17737c478bd9Sstevel@tonic-gate drop_and_bail: 1774f4b3ec61Sdh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 1775bd670b35SErik Nordmark ip_drop_packet(data_mp, B_TRUE, ira->ira_ill, counter, 1776f4b3ec61Sdh155122 &espstack->esp_dropper); 1777bd670b35SErik Nordmark BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards); 1778bd670b35SErik Nordmark return (NULL); 17797c478bd9Sstevel@tonic-gate } 17807c478bd9Sstevel@tonic-gate 17817c478bd9Sstevel@tonic-gate /* 17827c478bd9Sstevel@tonic-gate * Called upon failing the inbound ICV check. The message passed as 17837c478bd9Sstevel@tonic-gate * argument is freed. 17847c478bd9Sstevel@tonic-gate */ 17857c478bd9Sstevel@tonic-gate static void 1786bd670b35SErik Nordmark esp_log_bad_auth(mblk_t *mp, ip_recv_attr_t *ira) 17877c478bd9Sstevel@tonic-gate { 1788bd670b35SErik Nordmark ipsa_t *assoc = ira->ira_ipsec_esp_sa; 1789bd670b35SErik Nordmark netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack; 1790f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 1791f4b3ec61Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec; 17927c478bd9Sstevel@tonic-gate 17937c478bd9Sstevel@tonic-gate /* 17947c478bd9Sstevel@tonic-gate * Log the event. Don't print to the console, block 17957c478bd9Sstevel@tonic-gate * potential denial-of-service attack. 17967c478bd9Sstevel@tonic-gate */ 1797f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, bad_auth); 17987c478bd9Sstevel@tonic-gate 17997c478bd9Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 18007c478bd9Sstevel@tonic-gate "ESP Authentication failed for spi 0x%x, dst %s.\n", 1801f4b3ec61Sdh155122 assoc->ipsa_spi, assoc->ipsa_dstaddr, assoc->ipsa_addrfam, 1802f4b3ec61Sdh155122 espstack->ipsecesp_netstack); 18037c478bd9Sstevel@tonic-gate 1804f4b3ec61Sdh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 1805bd670b35SErik Nordmark ip_drop_packet(mp, B_TRUE, ira->ira_ill, 1806f4b3ec61Sdh155122 DROPPER(ipss, ipds_esp_bad_auth), 1807f4b3ec61Sdh155122 &espstack->esp_dropper); 18087c478bd9Sstevel@tonic-gate } 18097c478bd9Sstevel@tonic-gate 18107c478bd9Sstevel@tonic-gate 18117c478bd9Sstevel@tonic-gate /* 18127c478bd9Sstevel@tonic-gate * Invoked for outbound packets after ESP processing. If the packet 18137c478bd9Sstevel@tonic-gate * also requires AH, performs the AH SA selection and AH processing. 18147c478bd9Sstevel@tonic-gate * Returns B_TRUE if the AH processing was not needed or if it was 18157c478bd9Sstevel@tonic-gate * performed successfully. Returns B_FALSE and consumes the passed mblk 18167c478bd9Sstevel@tonic-gate * if AH processing was required but could not be performed. 1817bd670b35SErik Nordmark * 1818bd670b35SErik Nordmark * Returns data_mp unless data_mp was consumed/queued. 18197c478bd9Sstevel@tonic-gate */ 1820bd670b35SErik Nordmark static mblk_t * 1821bd670b35SErik Nordmark esp_do_outbound_ah(mblk_t *data_mp, ip_xmit_attr_t *ixa) 18227c478bd9Sstevel@tonic-gate { 18237c478bd9Sstevel@tonic-gate ipsec_action_t *ap; 18247c478bd9Sstevel@tonic-gate 1825bd670b35SErik Nordmark ap = ixa->ixa_ipsec_action; 18267c478bd9Sstevel@tonic-gate if (ap == NULL) { 1827bd670b35SErik Nordmark ipsec_policy_t *pp = ixa->ixa_ipsec_policy; 18287c478bd9Sstevel@tonic-gate ap = pp->ipsp_act; 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate if (!ap->ipa_want_ah) 1832bd670b35SErik Nordmark return (data_mp); 18337c478bd9Sstevel@tonic-gate 1834bd670b35SErik Nordmark /* 1835bd670b35SErik Nordmark * Normally the AH SA would have already been put in place 1836bd670b35SErik Nordmark * but it could have been flushed so we need to look for it. 1837bd670b35SErik Nordmark */ 1838bd670b35SErik Nordmark if (ixa->ixa_ipsec_ah_sa == NULL) { 1839bd670b35SErik Nordmark if (!ipsec_outbound_sa(data_mp, ixa, IPPROTO_AH)) { 1840bd670b35SErik Nordmark sadb_acquire(data_mp, ixa, B_TRUE, B_FALSE); 1841bd670b35SErik Nordmark return (NULL); 18427c478bd9Sstevel@tonic-gate } 18437c478bd9Sstevel@tonic-gate } 1844bd670b35SErik Nordmark ASSERT(ixa->ixa_ipsec_ah_sa != NULL); 18457c478bd9Sstevel@tonic-gate 1846bd670b35SErik Nordmark data_mp = ixa->ixa_ipsec_ah_sa->ipsa_output_func(data_mp, ixa); 1847bd670b35SErik Nordmark return (data_mp); 18487c478bd9Sstevel@tonic-gate } 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate /* 18527c478bd9Sstevel@tonic-gate * Kernel crypto framework callback invoked after completion of async 1853bd670b35SErik Nordmark * crypto requests for outbound packets. 18547c478bd9Sstevel@tonic-gate */ 18557c478bd9Sstevel@tonic-gate static void 1856bd670b35SErik Nordmark esp_kcf_callback_outbound(void *arg, int status) 18577c478bd9Sstevel@tonic-gate { 1858bd670b35SErik Nordmark mblk_t *mp = (mblk_t *)arg; 1859bd670b35SErik Nordmark mblk_t *async_mp; 1860bd670b35SErik Nordmark netstack_t *ns; 1861f4b3ec61Sdh155122 ipsec_stack_t *ipss; 1862bd670b35SErik Nordmark ipsecesp_stack_t *espstack; 1863bd670b35SErik Nordmark mblk_t *data_mp; 1864bd670b35SErik Nordmark ip_xmit_attr_t ixas; 1865bd670b35SErik Nordmark ipsec_crypto_t *ic; 1866bd670b35SErik Nordmark ill_t *ill; 1867f4b3ec61Sdh155122 1868f4b3ec61Sdh155122 /* 1869bd670b35SErik Nordmark * First remove the ipsec_crypto_t mblk 1870bd670b35SErik Nordmark * Note that we need to ipsec_free_crypto_data(mp) once done with ic. 1871f4b3ec61Sdh155122 */ 1872bd670b35SErik Nordmark async_mp = ipsec_remove_crypto_data(mp, &ic); 1873bd670b35SErik Nordmark ASSERT(async_mp != NULL); 1874f4b3ec61Sdh155122 1875bd670b35SErik Nordmark /* 1876bd670b35SErik Nordmark * Extract the ip_xmit_attr_t from the first mblk. 1877bd670b35SErik Nordmark * Verifies that the netstack and ill is still around; could 1878bd670b35SErik Nordmark * have vanished while kEf was doing its work. 1879bd670b35SErik Nordmark * On succesful return we have a nce_t and the ill/ipst can't 1880bd670b35SErik Nordmark * disappear until we do the nce_refrele in ixa_cleanup. 1881bd670b35SErik Nordmark */ 1882bd670b35SErik Nordmark data_mp = async_mp->b_cont; 1883bd670b35SErik Nordmark async_mp->b_cont = NULL; 1884bd670b35SErik Nordmark if (!ip_xmit_attr_from_mblk(async_mp, &ixas)) { 1885bd670b35SErik Nordmark /* Disappeared on us - no ill/ipst for MIB */ 1886bd670b35SErik Nordmark /* We have nowhere to do stats since ixa_ipst could be NULL */ 1887bd670b35SErik Nordmark if (ixas.ixa_nce != NULL) { 1888bd670b35SErik Nordmark ill = ixas.ixa_nce->nce_ill; 1889bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards); 1890bd670b35SErik Nordmark ip_drop_output("ipIfStatsOutDiscards", data_mp, ill); 1891bd670b35SErik Nordmark } 1892bd670b35SErik Nordmark freemsg(data_mp); 1893bd670b35SErik Nordmark goto done; 1894bd670b35SErik Nordmark } 1895bd670b35SErik Nordmark ns = ixas.ixa_ipst->ips_netstack; 1896f4b3ec61Sdh155122 espstack = ns->netstack_ipsecesp; 1897f4b3ec61Sdh155122 ipss = ns->netstack_ipsec; 1898bd670b35SErik Nordmark ill = ixas.ixa_nce->nce_ill; 1899f4b3ec61Sdh155122 19007c478bd9Sstevel@tonic-gate if (status == CRYPTO_SUCCESS) { 19017c478bd9Sstevel@tonic-gate /* 19027c478bd9Sstevel@tonic-gate * If a ICV was computed, it was stored by the 19037c478bd9Sstevel@tonic-gate * crypto framework at the end of the packet. 19047c478bd9Sstevel@tonic-gate */ 1905bd670b35SErik Nordmark ipha_t *ipha = (ipha_t *)data_mp->b_rptr; 19067c478bd9Sstevel@tonic-gate 1907bd670b35SErik Nordmark esp_set_usetime(ixas.ixa_ipsec_esp_sa, B_FALSE); 1908437220cdSdanmcd /* NAT-T packet. */ 1909bd670b35SErik Nordmark if (IPH_HDR_VERSION(ipha) == IP_VERSION && 1910bd670b35SErik Nordmark ipha->ipha_protocol == IPPROTO_UDP) 1911bd670b35SErik Nordmark esp_prepare_udp(ns, data_mp, ipha); 1912437220cdSdanmcd 19137c478bd9Sstevel@tonic-gate /* do AH processing if needed */ 1914bd670b35SErik Nordmark data_mp = esp_do_outbound_ah(data_mp, &ixas); 1915bd670b35SErik Nordmark if (data_mp == NULL) 1916bd670b35SErik Nordmark goto done; 1917bd670b35SErik Nordmark 1918bd670b35SErik Nordmark (void) ip_output_post_ipsec(data_mp, &ixas); 19197c478bd9Sstevel@tonic-gate } else { 1920bd670b35SErik Nordmark /* Outbound shouldn't see invalid MAC */ 1921bd670b35SErik Nordmark ASSERT(status != CRYPTO_INVALID_MAC); 1922bd670b35SErik Nordmark 1923bd670b35SErik Nordmark esp1dbg(espstack, 1924bd670b35SErik Nordmark ("esp_kcf_callback_outbound: crypto failed with 0x%x\n", 1925bd670b35SErik Nordmark status)); 1926bd670b35SErik Nordmark ESP_BUMP_STAT(espstack, crypto_failures); 1927bd670b35SErik Nordmark ESP_BUMP_STAT(espstack, out_discards); 1928bd670b35SErik Nordmark ip_drop_packet(data_mp, B_FALSE, ill, 1929bd670b35SErik Nordmark DROPPER(ipss, ipds_esp_crypto_failed), 1930bd670b35SErik Nordmark &espstack->esp_dropper); 1931bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards); 19327c478bd9Sstevel@tonic-gate } 1933bd670b35SErik Nordmark done: 1934bd670b35SErik Nordmark ixa_cleanup(&ixas); 1935bd670b35SErik Nordmark (void) ipsec_free_crypto_data(mp); 19367c478bd9Sstevel@tonic-gate } 19377c478bd9Sstevel@tonic-gate 1938bd670b35SErik Nordmark /* 1939bd670b35SErik Nordmark * Kernel crypto framework callback invoked after completion of async 1940bd670b35SErik Nordmark * crypto requests for inbound packets. 1941bd670b35SErik Nordmark */ 1942bd670b35SErik Nordmark static void 1943bd670b35SErik Nordmark esp_kcf_callback_inbound(void *arg, int status) 1944bd670b35SErik Nordmark { 1945bd670b35SErik Nordmark mblk_t *mp = (mblk_t *)arg; 1946bd670b35SErik Nordmark mblk_t *async_mp; 1947bd670b35SErik Nordmark netstack_t *ns; 1948bd670b35SErik Nordmark ipsecesp_stack_t *espstack; 1949bd670b35SErik Nordmark ipsec_stack_t *ipss; 1950bd670b35SErik Nordmark mblk_t *data_mp; 1951bd670b35SErik Nordmark ip_recv_attr_t iras; 1952bd670b35SErik Nordmark ipsec_crypto_t *ic; 1953bd670b35SErik Nordmark 1954bd670b35SErik Nordmark /* 1955bd670b35SErik Nordmark * First remove the ipsec_crypto_t mblk 1956bd670b35SErik Nordmark * Note that we need to ipsec_free_crypto_data(mp) once done with ic. 1957bd670b35SErik Nordmark */ 1958bd670b35SErik Nordmark async_mp = ipsec_remove_crypto_data(mp, &ic); 1959bd670b35SErik Nordmark ASSERT(async_mp != NULL); 1960bd670b35SErik Nordmark 1961bd670b35SErik Nordmark /* 1962bd670b35SErik Nordmark * Extract the ip_recv_attr_t from the first mblk. 1963bd670b35SErik Nordmark * Verifies that the netstack and ill is still around; could 1964bd670b35SErik Nordmark * have vanished while kEf was doing its work. 1965bd670b35SErik Nordmark */ 1966bd670b35SErik Nordmark data_mp = async_mp->b_cont; 1967bd670b35SErik Nordmark async_mp->b_cont = NULL; 1968bd670b35SErik Nordmark if (!ip_recv_attr_from_mblk(async_mp, &iras)) { 1969bd670b35SErik Nordmark /* The ill or ip_stack_t disappeared on us */ 1970bd670b35SErik Nordmark ip_drop_input("ip_recv_attr_from_mblk", data_mp, NULL); 1971bd670b35SErik Nordmark freemsg(data_mp); 1972bd670b35SErik Nordmark goto done; 1973bd670b35SErik Nordmark } 1974bd670b35SErik Nordmark 1975bd670b35SErik Nordmark ns = iras.ira_ill->ill_ipst->ips_netstack; 1976bd670b35SErik Nordmark espstack = ns->netstack_ipsecesp; 1977bd670b35SErik Nordmark ipss = ns->netstack_ipsec; 1978bd670b35SErik Nordmark 1979bd670b35SErik Nordmark if (status == CRYPTO_SUCCESS) { 1980bd670b35SErik Nordmark data_mp = esp_in_done(data_mp, &iras, ic); 1981bd670b35SErik Nordmark if (data_mp == NULL) 1982bd670b35SErik Nordmark goto done; 1983bd670b35SErik Nordmark 1984bd670b35SErik Nordmark /* finish IPsec processing */ 1985bd670b35SErik Nordmark ip_input_post_ipsec(data_mp, &iras); 19867c478bd9Sstevel@tonic-gate } else if (status == CRYPTO_INVALID_MAC) { 1987bd670b35SErik Nordmark esp_log_bad_auth(data_mp, &iras); 19887c478bd9Sstevel@tonic-gate } else { 1989f4b3ec61Sdh155122 esp1dbg(espstack, 1990f4b3ec61Sdh155122 ("esp_kcf_callback: crypto failed with 0x%x\n", 19917c478bd9Sstevel@tonic-gate status)); 1992f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, crypto_failures); 1993f4b3ec61Sdh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 1994bd670b35SErik Nordmark ip_drop_packet(data_mp, B_TRUE, iras.ira_ill, 1995f4b3ec61Sdh155122 DROPPER(ipss, ipds_esp_crypto_failed), 1996f4b3ec61Sdh155122 &espstack->esp_dropper); 1997bd670b35SErik Nordmark BUMP_MIB(iras.ira_ill->ill_ip_mib, ipIfStatsInDiscards); 19987c478bd9Sstevel@tonic-gate } 1999bd670b35SErik Nordmark done: 2000bd670b35SErik Nordmark ira_cleanup(&iras, B_TRUE); 2001bd670b35SErik Nordmark (void) ipsec_free_crypto_data(mp); 20027c478bd9Sstevel@tonic-gate } 20037c478bd9Sstevel@tonic-gate 20047c478bd9Sstevel@tonic-gate /* 20057c478bd9Sstevel@tonic-gate * Invoked on crypto framework failure during inbound and outbound processing. 20067c478bd9Sstevel@tonic-gate */ 20077c478bd9Sstevel@tonic-gate static void 2008bd670b35SErik Nordmark esp_crypto_failed(mblk_t *data_mp, boolean_t is_inbound, int kef_rc, 2009bd670b35SErik Nordmark ill_t *ill, ipsecesp_stack_t *espstack) 20107c478bd9Sstevel@tonic-gate { 2011f4b3ec61Sdh155122 ipsec_stack_t *ipss = espstack->ipsecesp_netstack->netstack_ipsec; 2012f4b3ec61Sdh155122 2013f4b3ec61Sdh155122 esp1dbg(espstack, ("crypto failed for %s ESP with 0x%x\n", 20147c478bd9Sstevel@tonic-gate is_inbound ? "inbound" : "outbound", kef_rc)); 2015bd670b35SErik Nordmark ip_drop_packet(data_mp, is_inbound, ill, 2016f4b3ec61Sdh155122 DROPPER(ipss, ipds_esp_crypto_failed), 2017f4b3ec61Sdh155122 &espstack->esp_dropper); 2018f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, crypto_failures); 20197c478bd9Sstevel@tonic-gate if (is_inbound) 2020f4b3ec61Sdh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 20217c478bd9Sstevel@tonic-gate else 2022f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, out_discards); 20237c478bd9Sstevel@tonic-gate } 20247c478bd9Sstevel@tonic-gate 2025bd670b35SErik Nordmark /* 2026bd670b35SErik Nordmark * A statement-equivalent macro, _cr MUST point to a modifiable 2027bd670b35SErik Nordmark * crypto_call_req_t. 2028bd670b35SErik Nordmark */ 2029bd670b35SErik Nordmark #define ESP_INIT_CALLREQ(_cr, _mp, _callback) \ 2030bd670b35SErik Nordmark (_cr)->cr_flag = CRYPTO_SKIP_REQID|CRYPTO_ALWAYS_QUEUE; \ 2031bd670b35SErik Nordmark (_cr)->cr_callback_arg = (_mp); \ 2032bd670b35SErik Nordmark (_cr)->cr_callback_func = (_callback) 20337c478bd9Sstevel@tonic-gate 20347c478bd9Sstevel@tonic-gate #define ESP_INIT_CRYPTO_MAC(mac, icvlen, icvbuf) { \ 20357c478bd9Sstevel@tonic-gate (mac)->cd_format = CRYPTO_DATA_RAW; \ 20367c478bd9Sstevel@tonic-gate (mac)->cd_offset = 0; \ 20377c478bd9Sstevel@tonic-gate (mac)->cd_length = icvlen; \ 20387c478bd9Sstevel@tonic-gate (mac)->cd_raw.iov_base = (char *)icvbuf; \ 20397c478bd9Sstevel@tonic-gate (mac)->cd_raw.iov_len = icvlen; \ 20407c478bd9Sstevel@tonic-gate } 20417c478bd9Sstevel@tonic-gate 20427c478bd9Sstevel@tonic-gate #define ESP_INIT_CRYPTO_DATA(data, mp, off, len) { \ 20437c478bd9Sstevel@tonic-gate if (MBLKL(mp) >= (len) + (off)) { \ 20447c478bd9Sstevel@tonic-gate (data)->cd_format = CRYPTO_DATA_RAW; \ 20457c478bd9Sstevel@tonic-gate (data)->cd_raw.iov_base = (char *)(mp)->b_rptr; \ 20467c478bd9Sstevel@tonic-gate (data)->cd_raw.iov_len = MBLKL(mp); \ 20477c478bd9Sstevel@tonic-gate (data)->cd_offset = off; \ 20487c478bd9Sstevel@tonic-gate } else { \ 20497c478bd9Sstevel@tonic-gate (data)->cd_format = CRYPTO_DATA_MBLK; \ 20507c478bd9Sstevel@tonic-gate (data)->cd_mp = mp; \ 20517c478bd9Sstevel@tonic-gate (data)->cd_offset = off; \ 20527c478bd9Sstevel@tonic-gate } \ 20537c478bd9Sstevel@tonic-gate (data)->cd_length = len; \ 20547c478bd9Sstevel@tonic-gate } 20557c478bd9Sstevel@tonic-gate 20567c478bd9Sstevel@tonic-gate #define ESP_INIT_CRYPTO_DUAL_DATA(data, mp, off1, len1, off2, len2) { \ 20577c478bd9Sstevel@tonic-gate (data)->dd_format = CRYPTO_DATA_MBLK; \ 20587c478bd9Sstevel@tonic-gate (data)->dd_mp = mp; \ 20597c478bd9Sstevel@tonic-gate (data)->dd_len1 = len1; \ 20607c478bd9Sstevel@tonic-gate (data)->dd_offset1 = off1; \ 20617c478bd9Sstevel@tonic-gate (data)->dd_len2 = len2; \ 20627c478bd9Sstevel@tonic-gate (data)->dd_offset2 = off2; \ 20637c478bd9Sstevel@tonic-gate } 20647c478bd9Sstevel@tonic-gate 2065bd670b35SErik Nordmark /* 2066bd670b35SErik Nordmark * Returns data_mp if successfully completed the request. Returns 2067bd670b35SErik Nordmark * NULL if it failed (and increments InDiscards) or if it is pending. 2068bd670b35SErik Nordmark */ 2069bd670b35SErik Nordmark static mblk_t * 2070bd670b35SErik Nordmark esp_submit_req_inbound(mblk_t *esp_mp, ip_recv_attr_t *ira, 2071bd670b35SErik Nordmark ipsa_t *assoc, uint_t esph_offset) 20727c478bd9Sstevel@tonic-gate { 20737c478bd9Sstevel@tonic-gate uint_t auth_offset, msg_len, auth_len; 2074bd670b35SErik Nordmark crypto_call_req_t call_req, *callrp; 2075bd670b35SErik Nordmark mblk_t *mp; 2076628b0c67SMark Fenwick esph_t *esph_ptr; 2077bd670b35SErik Nordmark int kef_rc; 20787c478bd9Sstevel@tonic-gate uint_t icv_len = assoc->ipsa_mac_len; 20797c478bd9Sstevel@tonic-gate crypto_ctx_template_t auth_ctx_tmpl; 2080bd670b35SErik Nordmark boolean_t do_auth, do_encr, force; 20817c478bd9Sstevel@tonic-gate uint_t encr_offset, encr_len; 20827c478bd9Sstevel@tonic-gate uint_t iv_len = assoc->ipsa_iv_len; 20837c478bd9Sstevel@tonic-gate crypto_ctx_template_t encr_ctx_tmpl; 2084bd670b35SErik Nordmark ipsec_crypto_t *ic, icstack; 2085628b0c67SMark Fenwick uchar_t *iv_ptr; 2086bd670b35SErik Nordmark netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack; 2087bd670b35SErik Nordmark ipsec_stack_t *ipss = ns->netstack_ipsec; 2088bd670b35SErik Nordmark ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 2089f4b3ec61Sdh155122 20907c478bd9Sstevel@tonic-gate do_auth = assoc->ipsa_auth_alg != SADB_AALG_NONE; 20917c478bd9Sstevel@tonic-gate do_encr = assoc->ipsa_encr_alg != SADB_EALG_NULL; 2092bd670b35SErik Nordmark force = (assoc->ipsa_flags & IPSA_F_ASYNC); 2093bd670b35SErik Nordmark 2094bd670b35SErik Nordmark #ifdef IPSEC_LATENCY_TEST 2095bd670b35SErik Nordmark kef_rc = CRYPTO_SUCCESS; 2096bd670b35SErik Nordmark #else 2097bd670b35SErik Nordmark kef_rc = CRYPTO_FAILED; 2098bd670b35SErik Nordmark #endif 20997c478bd9Sstevel@tonic-gate 21007c478bd9Sstevel@tonic-gate /* 21017c478bd9Sstevel@tonic-gate * An inbound packet is of the form: 2102bd670b35SErik Nordmark * [IP,options,ESP,IV,data,ICV,pad] 21037c478bd9Sstevel@tonic-gate */ 2104628b0c67SMark Fenwick esph_ptr = (esph_t *)(esp_mp->b_rptr + esph_offset); 2105628b0c67SMark Fenwick iv_ptr = (uchar_t *)(esph_ptr + 1); 2106628b0c67SMark Fenwick /* Packet length starting at IP header ending after ESP ICV. */ 21077c478bd9Sstevel@tonic-gate msg_len = MBLKL(esp_mp); 21087c478bd9Sstevel@tonic-gate 2109628b0c67SMark Fenwick encr_offset = esph_offset + sizeof (esph_t) + iv_len; 2110628b0c67SMark Fenwick encr_len = msg_len - encr_offset; 2111628b0c67SMark Fenwick 2112628b0c67SMark Fenwick /* 2113628b0c67SMark Fenwick * Counter mode algs need a nonce. This is setup in sadb_common_add(). 2114628b0c67SMark Fenwick * If for some reason we are using a SA which does not have a nonce 2115628b0c67SMark Fenwick * then we must fail here. 2116628b0c67SMark Fenwick */ 2117628b0c67SMark Fenwick if ((assoc->ipsa_flags & IPSA_F_COUNTERMODE) && 2118628b0c67SMark Fenwick (assoc->ipsa_nonce == NULL)) { 2119bd670b35SErik Nordmark ip_drop_packet(esp_mp, B_TRUE, ira->ira_ill, 2120628b0c67SMark Fenwick DROPPER(ipss, ipds_esp_nomem), &espstack->esp_dropper); 2121bd670b35SErik Nordmark return (NULL); 2122bd670b35SErik Nordmark } 2123bd670b35SErik Nordmark 2124bd670b35SErik Nordmark if (force) { 2125bd670b35SErik Nordmark /* We are doing asynch; allocate mblks to hold state */ 2126bd670b35SErik Nordmark if ((mp = ip_recv_attr_to_mblk(ira)) == NULL || 2127bd670b35SErik Nordmark (mp = ipsec_add_crypto_data(mp, &ic)) == NULL) { 2128bd670b35SErik Nordmark BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards); 2129bd670b35SErik Nordmark ip_drop_input("ipIfStatsInDiscards", esp_mp, 2130bd670b35SErik Nordmark ira->ira_ill); 2131bd670b35SErik Nordmark return (NULL); 2132bd670b35SErik Nordmark } 2133bd670b35SErik Nordmark linkb(mp, esp_mp); 2134bd670b35SErik Nordmark callrp = &call_req; 2135bd670b35SErik Nordmark ESP_INIT_CALLREQ(callrp, mp, esp_kcf_callback_inbound); 2136bd670b35SErik Nordmark } else { 2137bd670b35SErik Nordmark /* 2138bd670b35SErik Nordmark * If we know we are going to do sync then ipsec_crypto_t 2139bd670b35SErik Nordmark * should be on the stack. 2140bd670b35SErik Nordmark */ 2141bd670b35SErik Nordmark ic = &icstack; 2142bd670b35SErik Nordmark bzero(ic, sizeof (*ic)); 2143bd670b35SErik Nordmark callrp = NULL; 2144628b0c67SMark Fenwick } 2145628b0c67SMark Fenwick 21467c478bd9Sstevel@tonic-gate if (do_auth) { 21477c478bd9Sstevel@tonic-gate /* authentication context template */ 21487c478bd9Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH, 21497c478bd9Sstevel@tonic-gate auth_ctx_tmpl); 21507c478bd9Sstevel@tonic-gate 21517c478bd9Sstevel@tonic-gate /* ICV to be verified */ 2152bd670b35SErik Nordmark ESP_INIT_CRYPTO_MAC(&ic->ic_crypto_mac, 21537c478bd9Sstevel@tonic-gate icv_len, esp_mp->b_wptr - icv_len); 21547c478bd9Sstevel@tonic-gate 21557c478bd9Sstevel@tonic-gate /* authentication starts at the ESP header */ 21567c478bd9Sstevel@tonic-gate auth_offset = esph_offset; 21577c478bd9Sstevel@tonic-gate auth_len = msg_len - auth_offset - icv_len; 21587c478bd9Sstevel@tonic-gate if (!do_encr) { 21597c478bd9Sstevel@tonic-gate /* authentication only */ 21607c478bd9Sstevel@tonic-gate /* initialize input data argument */ 2161bd670b35SErik Nordmark ESP_INIT_CRYPTO_DATA(&ic->ic_crypto_data, 21627c478bd9Sstevel@tonic-gate esp_mp, auth_offset, auth_len); 21637c478bd9Sstevel@tonic-gate 21647c478bd9Sstevel@tonic-gate /* call the crypto framework */ 21657c478bd9Sstevel@tonic-gate kef_rc = crypto_mac_verify(&assoc->ipsa_amech, 2166bd670b35SErik Nordmark &ic->ic_crypto_data, 21677c478bd9Sstevel@tonic-gate &assoc->ipsa_kcfauthkey, auth_ctx_tmpl, 2168bd670b35SErik Nordmark &ic->ic_crypto_mac, callrp); 21697c478bd9Sstevel@tonic-gate } 21707c478bd9Sstevel@tonic-gate } 21717c478bd9Sstevel@tonic-gate 21727c478bd9Sstevel@tonic-gate if (do_encr) { 21737c478bd9Sstevel@tonic-gate /* encryption template */ 21747c478bd9Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_encrtmpl, IPSEC_ALG_ENCR, 21757c478bd9Sstevel@tonic-gate encr_ctx_tmpl); 21767c478bd9Sstevel@tonic-gate 2177628b0c67SMark Fenwick /* Call the nonce update function. Also passes in IV */ 2178628b0c67SMark Fenwick (assoc->ipsa_noncefunc)(assoc, (uchar_t *)esph_ptr, encr_len, 2179bd670b35SErik Nordmark iv_ptr, &ic->ic_cmm, &ic->ic_crypto_data); 21807c478bd9Sstevel@tonic-gate 21817c478bd9Sstevel@tonic-gate if (!do_auth) { 21827c478bd9Sstevel@tonic-gate /* decryption only */ 21837c478bd9Sstevel@tonic-gate /* initialize input data argument */ 2184bd670b35SErik Nordmark ESP_INIT_CRYPTO_DATA(&ic->ic_crypto_data, 21857c478bd9Sstevel@tonic-gate esp_mp, encr_offset, encr_len); 21867c478bd9Sstevel@tonic-gate 21877c478bd9Sstevel@tonic-gate /* call the crypto framework */ 2188628b0c67SMark Fenwick kef_rc = crypto_decrypt((crypto_mechanism_t *) 2189bd670b35SErik Nordmark &ic->ic_cmm, &ic->ic_crypto_data, 21907c478bd9Sstevel@tonic-gate &assoc->ipsa_kcfencrkey, encr_ctx_tmpl, 2191bd670b35SErik Nordmark NULL, callrp); 21927c478bd9Sstevel@tonic-gate } 21937c478bd9Sstevel@tonic-gate } 21947c478bd9Sstevel@tonic-gate 21957c478bd9Sstevel@tonic-gate if (do_auth && do_encr) { 21967c478bd9Sstevel@tonic-gate /* dual operation */ 21977c478bd9Sstevel@tonic-gate /* initialize input data argument */ 2198bd670b35SErik Nordmark ESP_INIT_CRYPTO_DUAL_DATA(&ic->ic_crypto_dual_data, 21997c478bd9Sstevel@tonic-gate esp_mp, auth_offset, auth_len, 22007c478bd9Sstevel@tonic-gate encr_offset, encr_len - icv_len); 22017c478bd9Sstevel@tonic-gate 22027c478bd9Sstevel@tonic-gate /* specify IV */ 2203bd670b35SErik Nordmark ic->ic_crypto_dual_data.dd_miscdata = (char *)iv_ptr; 22047c478bd9Sstevel@tonic-gate 22057c478bd9Sstevel@tonic-gate /* call the framework */ 22067c478bd9Sstevel@tonic-gate kef_rc = crypto_mac_verify_decrypt(&assoc->ipsa_amech, 2207bd670b35SErik Nordmark &assoc->ipsa_emech, &ic->ic_crypto_dual_data, 22087c478bd9Sstevel@tonic-gate &assoc->ipsa_kcfauthkey, &assoc->ipsa_kcfencrkey, 2209bd670b35SErik Nordmark auth_ctx_tmpl, encr_ctx_tmpl, &ic->ic_crypto_mac, 2210bd670b35SErik Nordmark NULL, callrp); 22117c478bd9Sstevel@tonic-gate } 22127c478bd9Sstevel@tonic-gate 22137c478bd9Sstevel@tonic-gate switch (kef_rc) { 22147c478bd9Sstevel@tonic-gate case CRYPTO_SUCCESS: 2215f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, crypto_sync); 2216bd670b35SErik Nordmark esp_mp = esp_in_done(esp_mp, ira, ic); 2217bd670b35SErik Nordmark if (force) { 2218bd670b35SErik Nordmark /* Free mp after we are done with ic */ 2219bd670b35SErik Nordmark mp = ipsec_free_crypto_data(mp); 2220bd670b35SErik Nordmark (void) ip_recv_attr_free_mblk(mp); 2221bd670b35SErik Nordmark } 2222bd670b35SErik Nordmark return (esp_mp); 22237c478bd9Sstevel@tonic-gate case CRYPTO_QUEUED: 2224bd670b35SErik Nordmark /* esp_kcf_callback_inbound() will be invoked on completion */ 2225f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, crypto_async); 2226bd670b35SErik Nordmark return (NULL); 22277c478bd9Sstevel@tonic-gate case CRYPTO_INVALID_MAC: 2228bd670b35SErik Nordmark if (force) { 2229bd670b35SErik Nordmark mp = ipsec_free_crypto_data(mp); 2230bd670b35SErik Nordmark esp_mp = ip_recv_attr_free_mblk(mp); 2231bd670b35SErik Nordmark } 2232f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, crypto_sync); 2233bd670b35SErik Nordmark BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards); 2234bd670b35SErik Nordmark esp_log_bad_auth(esp_mp, ira); 2235bd670b35SErik Nordmark /* esp_mp was passed to ip_drop_packet */ 2236bd670b35SErik Nordmark return (NULL); 22377c478bd9Sstevel@tonic-gate } 22387c478bd9Sstevel@tonic-gate 2239bd984e57SDan McDonald if (force) { 2240bd670b35SErik Nordmark mp = ipsec_free_crypto_data(mp); 2241bd670b35SErik Nordmark esp_mp = ip_recv_attr_free_mblk(mp); 2242bd984e57SDan McDonald } 2243bd670b35SErik Nordmark BUMP_MIB(ira->ira_ill->ill_ip_mib, ipIfStatsInDiscards); 2244bd670b35SErik Nordmark esp_crypto_failed(esp_mp, B_TRUE, kef_rc, ira->ira_ill, espstack); 2245bd670b35SErik Nordmark /* esp_mp was passed to ip_drop_packet */ 2246bd670b35SErik Nordmark return (NULL); 22477c478bd9Sstevel@tonic-gate } 22487c478bd9Sstevel@tonic-gate 2249437220cdSdanmcd /* 2250437220cdSdanmcd * Compute the IP and UDP checksums -- common code for both keepalives and 2251437220cdSdanmcd * actual ESP-in-UDP packets. Be flexible with multiple mblks because ESP 2252437220cdSdanmcd * uses mblk-insertion to insert the UDP header. 2253437220cdSdanmcd * TODO - If there is an easy way to prep a packet for HW checksums, make 2254437220cdSdanmcd * it happen here. 2255bd670b35SErik Nordmark * Note that this is used before both before calling ip_output_simple and 2256bd670b35SErik Nordmark * in the esp datapath. The former could use IXAF_SET_ULP_CKSUM but not the 2257bd670b35SErik Nordmark * latter. 2258437220cdSdanmcd */ 2259437220cdSdanmcd static void 2260437220cdSdanmcd esp_prepare_udp(netstack_t *ns, mblk_t *mp, ipha_t *ipha) 2261437220cdSdanmcd { 2262437220cdSdanmcd int offset; 2263437220cdSdanmcd uint32_t cksum; 2264437220cdSdanmcd uint16_t *arr; 2265437220cdSdanmcd mblk_t *udpmp = mp; 226687e10ffaSwy83408 uint_t hlen = IPH_HDR_LENGTH(ipha); 2267437220cdSdanmcd 2268437220cdSdanmcd ASSERT(MBLKL(mp) >= sizeof (ipha_t)); 2269437220cdSdanmcd 2270437220cdSdanmcd ipha->ipha_hdr_checksum = 0; 2271437220cdSdanmcd ipha->ipha_hdr_checksum = ip_csum_hdr(ipha); 2272437220cdSdanmcd 2273437220cdSdanmcd if (ns->netstack_udp->us_do_checksum) { 2274437220cdSdanmcd ASSERT(MBLKL(udpmp) >= sizeof (udpha_t)); 2275437220cdSdanmcd /* arr points to the IP header. */ 2276437220cdSdanmcd arr = (uint16_t *)ipha; 2277437220cdSdanmcd IP_STAT(ns->netstack_ip, ip_out_sw_cksum); 2278bd670b35SErik Nordmark IP_STAT_UPDATE(ns->netstack_ip, ip_out_sw_cksum_bytes, 227987e10ffaSwy83408 ntohs(htons(ipha->ipha_length) - hlen)); 2280437220cdSdanmcd /* arr[6-9] are the IP addresses. */ 2281437220cdSdanmcd cksum = IP_UDP_CSUM_COMP + arr[6] + arr[7] + arr[8] + arr[9] + 228287e10ffaSwy83408 ntohs(htons(ipha->ipha_length) - hlen); 228387e10ffaSwy83408 cksum = IP_CSUM(mp, hlen, cksum); 228487e10ffaSwy83408 offset = hlen + UDP_CHECKSUM_OFFSET; 2285437220cdSdanmcd while (offset >= MBLKL(udpmp)) { 2286437220cdSdanmcd offset -= MBLKL(udpmp); 2287437220cdSdanmcd udpmp = udpmp->b_cont; 2288437220cdSdanmcd } 2289437220cdSdanmcd /* arr points to the UDP header's checksum field. */ 2290437220cdSdanmcd arr = (uint16_t *)(udpmp->b_rptr + offset); 2291437220cdSdanmcd *arr = cksum; 2292437220cdSdanmcd } 2293437220cdSdanmcd } 2294437220cdSdanmcd 2295437220cdSdanmcd /* 229673184bc7SDan McDonald * taskq handler so we can send the NAT-T keepalive on a separate thread. 229773184bc7SDan McDonald */ 229873184bc7SDan McDonald static void 229973184bc7SDan McDonald actually_send_keepalive(void *arg) 230073184bc7SDan McDonald { 2301bd670b35SErik Nordmark mblk_t *mp = (mblk_t *)arg; 2302bd670b35SErik Nordmark ip_xmit_attr_t ixas; 230373184bc7SDan McDonald netstack_t *ns; 2304bd670b35SErik Nordmark netstackid_t stackid; 230573184bc7SDan McDonald 2306bd670b35SErik Nordmark stackid = (netstackid_t)(uintptr_t)mp->b_prev; 2307bd670b35SErik Nordmark mp->b_prev = NULL; 2308bd670b35SErik Nordmark ns = netstack_find_by_stackid(stackid); 2309bd670b35SErik Nordmark if (ns == NULL) { 2310bd670b35SErik Nordmark /* Disappeared */ 2311bd670b35SErik Nordmark ip_drop_output("ipIfStatsOutDiscards", mp, NULL); 2312bd670b35SErik Nordmark freemsg(mp); 231373184bc7SDan McDonald return; 231473184bc7SDan McDonald } 231573184bc7SDan McDonald 2316bd670b35SErik Nordmark bzero(&ixas, sizeof (ixas)); 2317bd670b35SErik Nordmark ixas.ixa_zoneid = ALL_ZONES; 2318bd670b35SErik Nordmark ixas.ixa_cred = kcred; 2319bd670b35SErik Nordmark ixas.ixa_cpid = NOPID; 2320bd670b35SErik Nordmark ixas.ixa_tsl = NULL; 2321bd670b35SErik Nordmark ixas.ixa_ipst = ns->netstack_ip; 2322bd670b35SErik Nordmark /* No ULP checksum; done by esp_prepare_udp */ 232344b099c4SSowmini Varadhan ixas.ixa_flags = (IXAF_IS_IPV4 | IXAF_NO_IPSEC | IXAF_VERIFY_SOURCE); 2324bd670b35SErik Nordmark 2325bd670b35SErik Nordmark (void) ip_output_simple(mp, &ixas); 2326bd670b35SErik Nordmark ixa_cleanup(&ixas); 232773184bc7SDan McDonald netstack_rele(ns); 232873184bc7SDan McDonald } 232973184bc7SDan McDonald 233073184bc7SDan McDonald /* 2331bd670b35SErik Nordmark * Send a one-byte UDP NAT-T keepalive. 2332437220cdSdanmcd */ 2333437220cdSdanmcd void 2334437220cdSdanmcd ipsecesp_send_keepalive(ipsa_t *assoc) 2335437220cdSdanmcd { 2336bd670b35SErik Nordmark mblk_t *mp; 2337437220cdSdanmcd ipha_t *ipha; 2338437220cdSdanmcd udpha_t *udpha; 2339bd670b35SErik Nordmark netstack_t *ns = assoc->ipsa_netstack; 2340437220cdSdanmcd 23410c0328cdSBill Sommerfeld ASSERT(MUTEX_NOT_HELD(&assoc->ipsa_lock)); 2342437220cdSdanmcd 2343437220cdSdanmcd mp = allocb(sizeof (ipha_t) + sizeof (udpha_t) + 1, BPRI_HI); 2344437220cdSdanmcd if (mp == NULL) 2345437220cdSdanmcd return; 2346437220cdSdanmcd ipha = (ipha_t *)mp->b_rptr; 2347437220cdSdanmcd ipha->ipha_version_and_hdr_length = IP_SIMPLE_HDR_VERSION; 2348437220cdSdanmcd ipha->ipha_type_of_service = 0; 2349437220cdSdanmcd ipha->ipha_length = htons(sizeof (ipha_t) + sizeof (udpha_t) + 1); 2350437220cdSdanmcd /* Use the low-16 of the SPI so we have some clue where it came from. */ 2351437220cdSdanmcd ipha->ipha_ident = *(((uint16_t *)(&assoc->ipsa_spi)) + 1); 2352437220cdSdanmcd ipha->ipha_fragment_offset_and_flags = 0; /* Too small to fragment! */ 2353437220cdSdanmcd ipha->ipha_ttl = 0xFF; 2354437220cdSdanmcd ipha->ipha_protocol = IPPROTO_UDP; 2355437220cdSdanmcd ipha->ipha_hdr_checksum = 0; 2356437220cdSdanmcd ipha->ipha_src = assoc->ipsa_srcaddr[0]; 2357437220cdSdanmcd ipha->ipha_dst = assoc->ipsa_dstaddr[0]; 2358437220cdSdanmcd udpha = (udpha_t *)(ipha + 1); 2359437220cdSdanmcd udpha->uha_src_port = (assoc->ipsa_local_nat_port != 0) ? 2360437220cdSdanmcd assoc->ipsa_local_nat_port : htons(IPPORT_IKE_NATT); 2361437220cdSdanmcd udpha->uha_dst_port = (assoc->ipsa_remote_nat_port != 0) ? 2362437220cdSdanmcd assoc->ipsa_remote_nat_port : htons(IPPORT_IKE_NATT); 2363437220cdSdanmcd udpha->uha_length = htons(sizeof (udpha_t) + 1); 2364437220cdSdanmcd udpha->uha_checksum = 0; 2365437220cdSdanmcd mp->b_wptr = (uint8_t *)(udpha + 1); 2366437220cdSdanmcd *(mp->b_wptr++) = 0xFF; 2367437220cdSdanmcd 2368bd670b35SErik Nordmark esp_prepare_udp(ns, mp, ipha); 2369437220cdSdanmcd 237073184bc7SDan McDonald /* 237173184bc7SDan McDonald * We're holding an isaf_t bucket lock, so pawn off the actual 237273184bc7SDan McDonald * packet transmission to another thread. Just in case syncq 237373184bc7SDan McDonald * processing causes a same-bucket packet to be processed. 237473184bc7SDan McDonald */ 2375bd670b35SErik Nordmark mp->b_prev = (mblk_t *)(uintptr_t)ns->netstack_stackid; 2376bd670b35SErik Nordmark 2377bd670b35SErik Nordmark if (taskq_dispatch(esp_taskq, actually_send_keepalive, mp, 237873184bc7SDan McDonald TQ_NOSLEEP) == 0) { 237973184bc7SDan McDonald /* Assume no memory if taskq_dispatch() fails. */ 2380bd670b35SErik Nordmark mp->b_prev = NULL; 2381bd670b35SErik Nordmark ip_drop_packet(mp, B_FALSE, NULL, 2382bd670b35SErik Nordmark DROPPER(ns->netstack_ipsec, ipds_esp_nomem), 2383bd670b35SErik Nordmark &ns->netstack_ipsecesp->esp_dropper); 238473184bc7SDan McDonald } 2385437220cdSdanmcd } 2386437220cdSdanmcd 2387bd670b35SErik Nordmark /* 2388bd670b35SErik Nordmark * Returns mp if successfully completed the request. Returns 2389bd670b35SErik Nordmark * NULL if it failed (and increments InDiscards) or if it is pending. 2390bd670b35SErik Nordmark */ 2391bd670b35SErik Nordmark static mblk_t * 2392bd670b35SErik Nordmark esp_submit_req_outbound(mblk_t *data_mp, ip_xmit_attr_t *ixa, ipsa_t *assoc, 2393bd670b35SErik Nordmark uchar_t *icv_buf, uint_t payload_len) 23947c478bd9Sstevel@tonic-gate { 23957c478bd9Sstevel@tonic-gate uint_t auth_len; 2396bd670b35SErik Nordmark crypto_call_req_t call_req, *callrp; 2397bd670b35SErik Nordmark mblk_t *esp_mp; 2398628b0c67SMark Fenwick esph_t *esph_ptr; 2399bd670b35SErik Nordmark mblk_t *mp; 24007c478bd9Sstevel@tonic-gate int kef_rc = CRYPTO_FAILED; 24017c478bd9Sstevel@tonic-gate uint_t icv_len = assoc->ipsa_mac_len; 24027c478bd9Sstevel@tonic-gate crypto_ctx_template_t auth_ctx_tmpl; 2403bd670b35SErik Nordmark boolean_t do_auth, do_encr, force; 24047c478bd9Sstevel@tonic-gate uint_t iv_len = assoc->ipsa_iv_len; 24057c478bd9Sstevel@tonic-gate crypto_ctx_template_t encr_ctx_tmpl; 24067c478bd9Sstevel@tonic-gate boolean_t is_natt = ((assoc->ipsa_flags & IPSA_F_NATT) != 0); 24077c478bd9Sstevel@tonic-gate size_t esph_offset = (is_natt ? UDPH_SIZE : 0); 2408bd670b35SErik Nordmark netstack_t *ns = ixa->ixa_ipst->ips_netstack; 2409f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 2410bd670b35SErik Nordmark ipsec_crypto_t *ic, icstack; 2411628b0c67SMark Fenwick uchar_t *iv_ptr; 2412628b0c67SMark Fenwick crypto_data_t *cd_ptr = NULL; 2413bd670b35SErik Nordmark ill_t *ill = ixa->ixa_nce->nce_ill; 2414bd670b35SErik Nordmark ipsec_stack_t *ipss = ns->netstack_ipsec; 24157c478bd9Sstevel@tonic-gate 2416f4b3ec61Sdh155122 esp3dbg(espstack, ("esp_submit_req_outbound:%s", 2417f4b3ec61Sdh155122 is_natt ? "natt" : "not natt")); 24187c478bd9Sstevel@tonic-gate 24197c478bd9Sstevel@tonic-gate do_encr = assoc->ipsa_encr_alg != SADB_EALG_NULL; 24207c478bd9Sstevel@tonic-gate do_auth = assoc->ipsa_auth_alg != SADB_AALG_NONE; 2421bd670b35SErik Nordmark force = (assoc->ipsa_flags & IPSA_F_ASYNC); 2422bd670b35SErik Nordmark 2423bd670b35SErik Nordmark #ifdef IPSEC_LATENCY_TEST 2424bd670b35SErik Nordmark kef_rc = CRYPTO_SUCCESS; 2425bd670b35SErik Nordmark #else 2426bd670b35SErik Nordmark kef_rc = CRYPTO_FAILED; 2427bd670b35SErik Nordmark #endif 24287c478bd9Sstevel@tonic-gate 24297c478bd9Sstevel@tonic-gate /* 24307c478bd9Sstevel@tonic-gate * Outbound IPsec packets are of the form: 2431bd670b35SErik Nordmark * [IP,options] -> [ESP,IV] -> [data] -> [pad,ICV] 24327c478bd9Sstevel@tonic-gate * unless it's NATT, then it's 2433bd670b35SErik Nordmark * [IP,options] -> [udp][ESP,IV] -> [data] -> [pad,ICV] 24347c478bd9Sstevel@tonic-gate * Get a pointer to the mblk containing the ESP header. 24357c478bd9Sstevel@tonic-gate */ 2436bd670b35SErik Nordmark ASSERT(data_mp->b_cont != NULL); 2437bd670b35SErik Nordmark esp_mp = data_mp->b_cont; 2438628b0c67SMark Fenwick esph_ptr = (esph_t *)(esp_mp->b_rptr + esph_offset); 2439628b0c67SMark Fenwick iv_ptr = (uchar_t *)(esph_ptr + 1); 2440628b0c67SMark Fenwick 2441628b0c67SMark Fenwick /* 2442628b0c67SMark Fenwick * Combined mode algs need a nonce. This is setup in sadb_common_add(). 2443628b0c67SMark Fenwick * If for some reason we are using a SA which does not have a nonce 2444628b0c67SMark Fenwick * then we must fail here. 2445628b0c67SMark Fenwick */ 2446628b0c67SMark Fenwick if ((assoc->ipsa_flags & IPSA_F_COUNTERMODE) && 2447628b0c67SMark Fenwick (assoc->ipsa_nonce == NULL)) { 2448bd670b35SErik Nordmark ip_drop_packet(data_mp, B_FALSE, NULL, 2449628b0c67SMark Fenwick DROPPER(ipss, ipds_esp_nomem), &espstack->esp_dropper); 2450bd670b35SErik Nordmark return (NULL); 2451628b0c67SMark Fenwick } 24527c478bd9Sstevel@tonic-gate 2453bd670b35SErik Nordmark if (force) { 2454bd670b35SErik Nordmark /* We are doing asynch; allocate mblks to hold state */ 2455bd670b35SErik Nordmark if ((mp = ip_xmit_attr_to_mblk(ixa)) == NULL || 2456bd670b35SErik Nordmark (mp = ipsec_add_crypto_data(mp, &ic)) == NULL) { 2457bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards); 2458bd670b35SErik Nordmark ip_drop_output("ipIfStatsOutDiscards", data_mp, ill); 2459bd670b35SErik Nordmark freemsg(data_mp); 2460bd670b35SErik Nordmark return (NULL); 2461bd670b35SErik Nordmark } 2462bd670b35SErik Nordmark 2463bd670b35SErik Nordmark linkb(mp, data_mp); 2464bd670b35SErik Nordmark callrp = &call_req; 2465bd670b35SErik Nordmark ESP_INIT_CALLREQ(callrp, mp, esp_kcf_callback_outbound); 2466bd670b35SErik Nordmark } else { 2467bd670b35SErik Nordmark /* 2468bd670b35SErik Nordmark * If we know we are going to do sync then ipsec_crypto_t 2469bd670b35SErik Nordmark * should be on the stack. 2470bd670b35SErik Nordmark */ 2471bd670b35SErik Nordmark ic = &icstack; 2472bd670b35SErik Nordmark bzero(ic, sizeof (*ic)); 2473bd670b35SErik Nordmark callrp = NULL; 2474bd670b35SErik Nordmark } 2475bd670b35SErik Nordmark 24767c478bd9Sstevel@tonic-gate 24777c478bd9Sstevel@tonic-gate if (do_auth) { 24787c478bd9Sstevel@tonic-gate /* authentication context template */ 24797c478bd9Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH, 24807c478bd9Sstevel@tonic-gate auth_ctx_tmpl); 24817c478bd9Sstevel@tonic-gate 24827c478bd9Sstevel@tonic-gate /* where to store the computed mac */ 2483bd670b35SErik Nordmark ESP_INIT_CRYPTO_MAC(&ic->ic_crypto_mac, 24847c478bd9Sstevel@tonic-gate icv_len, icv_buf); 24857c478bd9Sstevel@tonic-gate 24867c478bd9Sstevel@tonic-gate /* authentication starts at the ESP header */ 2487a86080f9Sdanmcd auth_len = payload_len + iv_len + sizeof (esph_t); 24887c478bd9Sstevel@tonic-gate if (!do_encr) { 24897c478bd9Sstevel@tonic-gate /* authentication only */ 24907c478bd9Sstevel@tonic-gate /* initialize input data argument */ 2491bd670b35SErik Nordmark ESP_INIT_CRYPTO_DATA(&ic->ic_crypto_data, 24927c478bd9Sstevel@tonic-gate esp_mp, esph_offset, auth_len); 24937c478bd9Sstevel@tonic-gate 24947c478bd9Sstevel@tonic-gate /* call the crypto framework */ 24957c478bd9Sstevel@tonic-gate kef_rc = crypto_mac(&assoc->ipsa_amech, 2496bd670b35SErik Nordmark &ic->ic_crypto_data, 24977c478bd9Sstevel@tonic-gate &assoc->ipsa_kcfauthkey, auth_ctx_tmpl, 2498bd670b35SErik Nordmark &ic->ic_crypto_mac, callrp); 24997c478bd9Sstevel@tonic-gate } 25007c478bd9Sstevel@tonic-gate } 25017c478bd9Sstevel@tonic-gate 25027c478bd9Sstevel@tonic-gate if (do_encr) { 25037c478bd9Sstevel@tonic-gate /* encryption context template */ 25047c478bd9Sstevel@tonic-gate IPSEC_CTX_TMPL(assoc, ipsa_encrtmpl, IPSEC_ALG_ENCR, 25057c478bd9Sstevel@tonic-gate encr_ctx_tmpl); 2506628b0c67SMark Fenwick /* Call the nonce update function. */ 2507628b0c67SMark Fenwick (assoc->ipsa_noncefunc)(assoc, (uchar_t *)esph_ptr, payload_len, 2508bd670b35SErik Nordmark iv_ptr, &ic->ic_cmm, &ic->ic_crypto_data); 25097c478bd9Sstevel@tonic-gate 25107c478bd9Sstevel@tonic-gate if (!do_auth) { 25117c478bd9Sstevel@tonic-gate /* encryption only, skip mblk that contains ESP hdr */ 25127c478bd9Sstevel@tonic-gate /* initialize input data argument */ 2513bd670b35SErik Nordmark ESP_INIT_CRYPTO_DATA(&ic->ic_crypto_data, 2514bd670b35SErik Nordmark esp_mp->b_cont, 0, payload_len); 25157c478bd9Sstevel@tonic-gate 2516628b0c67SMark Fenwick /* 2517628b0c67SMark Fenwick * For combined mode ciphers, the ciphertext is the same 2518628b0c67SMark Fenwick * size as the clear text, the ICV should follow the 2519628b0c67SMark Fenwick * ciphertext. To convince the kcf to allow in-line 2520628b0c67SMark Fenwick * encryption, with an ICV, use ipsec_out_crypto_mac 2521628b0c67SMark Fenwick * to point to the same buffer as the data. The calling 2522628b0c67SMark Fenwick * function need to ensure the buffer is large enough to 2523628b0c67SMark Fenwick * include the ICV. 2524628b0c67SMark Fenwick * 2525628b0c67SMark Fenwick * The IV is already written to the packet buffer, the 2526628b0c67SMark Fenwick * nonce setup function copied it to the params struct 2527628b0c67SMark Fenwick * for the cipher to use. 2528628b0c67SMark Fenwick */ 2529628b0c67SMark Fenwick if (assoc->ipsa_flags & IPSA_F_COMBINED) { 2530bd670b35SErik Nordmark bcopy(&ic->ic_crypto_data, 2531bd670b35SErik Nordmark &ic->ic_crypto_mac, 2532628b0c67SMark Fenwick sizeof (crypto_data_t)); 2533bd670b35SErik Nordmark ic->ic_crypto_mac.cd_length = 2534628b0c67SMark Fenwick payload_len + icv_len; 2535bd670b35SErik Nordmark cd_ptr = &ic->ic_crypto_mac; 2536628b0c67SMark Fenwick } 25377c478bd9Sstevel@tonic-gate 25387c478bd9Sstevel@tonic-gate /* call the crypto framework */ 2539628b0c67SMark Fenwick kef_rc = crypto_encrypt((crypto_mechanism_t *) 2540bd670b35SErik Nordmark &ic->ic_cmm, &ic->ic_crypto_data, 25417c478bd9Sstevel@tonic-gate &assoc->ipsa_kcfencrkey, encr_ctx_tmpl, 2542bd670b35SErik Nordmark cd_ptr, callrp); 2543628b0c67SMark Fenwick 25447c478bd9Sstevel@tonic-gate } 25457c478bd9Sstevel@tonic-gate } 25467c478bd9Sstevel@tonic-gate 25477c478bd9Sstevel@tonic-gate if (do_auth && do_encr) { 25487c478bd9Sstevel@tonic-gate /* 25497c478bd9Sstevel@tonic-gate * Encryption and authentication: 25507c478bd9Sstevel@tonic-gate * Pass the pointer to the mblk chain starting at the ESP 25517c478bd9Sstevel@tonic-gate * header to the framework. Skip the ESP header mblk 25527c478bd9Sstevel@tonic-gate * for encryption, which is reflected by an encryption 25537c478bd9Sstevel@tonic-gate * offset equal to the length of that mblk. Start 25547c478bd9Sstevel@tonic-gate * the authentication at the ESP header, i.e. use an 25557c478bd9Sstevel@tonic-gate * authentication offset of zero. 25567c478bd9Sstevel@tonic-gate */ 2557bd670b35SErik Nordmark ESP_INIT_CRYPTO_DUAL_DATA(&ic->ic_crypto_dual_data, 25587c478bd9Sstevel@tonic-gate esp_mp, MBLKL(esp_mp), payload_len, esph_offset, auth_len); 25597c478bd9Sstevel@tonic-gate 25607c478bd9Sstevel@tonic-gate /* specify IV */ 2561bd670b35SErik Nordmark ic->ic_crypto_dual_data.dd_miscdata = (char *)iv_ptr; 25627c478bd9Sstevel@tonic-gate 25637c478bd9Sstevel@tonic-gate /* call the framework */ 25647c478bd9Sstevel@tonic-gate kef_rc = crypto_encrypt_mac(&assoc->ipsa_emech, 25657c478bd9Sstevel@tonic-gate &assoc->ipsa_amech, NULL, 25667c478bd9Sstevel@tonic-gate &assoc->ipsa_kcfencrkey, &assoc->ipsa_kcfauthkey, 25677c478bd9Sstevel@tonic-gate encr_ctx_tmpl, auth_ctx_tmpl, 2568bd670b35SErik Nordmark &ic->ic_crypto_dual_data, 2569bd670b35SErik Nordmark &ic->ic_crypto_mac, callrp); 25707c478bd9Sstevel@tonic-gate } 25717c478bd9Sstevel@tonic-gate 25727c478bd9Sstevel@tonic-gate switch (kef_rc) { 25737c478bd9Sstevel@tonic-gate case CRYPTO_SUCCESS: 2574f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, crypto_sync); 2575437220cdSdanmcd esp_set_usetime(assoc, B_FALSE); 2576bd670b35SErik Nordmark if (force) { 2577bd670b35SErik Nordmark mp = ipsec_free_crypto_data(mp); 2578bd670b35SErik Nordmark data_mp = ip_xmit_attr_free_mblk(mp); 2579bd670b35SErik Nordmark } 2580437220cdSdanmcd if (is_natt) 2581bd670b35SErik Nordmark esp_prepare_udp(ns, data_mp, (ipha_t *)data_mp->b_rptr); 2582bd670b35SErik Nordmark return (data_mp); 25837c478bd9Sstevel@tonic-gate case CRYPTO_QUEUED: 2584bd670b35SErik Nordmark /* esp_kcf_callback_outbound() will be invoked on completion */ 2585f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, crypto_async); 2586bd670b35SErik Nordmark return (NULL); 25877c478bd9Sstevel@tonic-gate } 25887c478bd9Sstevel@tonic-gate 2589bd670b35SErik Nordmark if (force) { 2590bd670b35SErik Nordmark mp = ipsec_free_crypto_data(mp); 2591bd670b35SErik Nordmark data_mp = ip_xmit_attr_free_mblk(mp); 2592bd670b35SErik Nordmark } 2593bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards); 2594bd670b35SErik Nordmark esp_crypto_failed(data_mp, B_FALSE, kef_rc, NULL, espstack); 2595bd670b35SErik Nordmark /* data_mp was passed to ip_drop_packet */ 2596bd670b35SErik Nordmark return (NULL); 25977c478bd9Sstevel@tonic-gate } 25987c478bd9Sstevel@tonic-gate 25997c478bd9Sstevel@tonic-gate /* 26007c478bd9Sstevel@tonic-gate * Handle outbound IPsec processing for IPv4 and IPv6 2601bd670b35SErik Nordmark * 2602bd670b35SErik Nordmark * Returns data_mp if successfully completed the request. Returns 2603bd670b35SErik Nordmark * NULL if it failed (and increments InDiscards) or if it is pending. 26047c478bd9Sstevel@tonic-gate */ 2605bd670b35SErik Nordmark static mblk_t * 2606bd670b35SErik Nordmark esp_outbound(mblk_t *data_mp, ip_xmit_attr_t *ixa) 26077c478bd9Sstevel@tonic-gate { 2608bd670b35SErik Nordmark mblk_t *espmp, *tailmp; 26097c478bd9Sstevel@tonic-gate ipha_t *ipha; 26107c478bd9Sstevel@tonic-gate ip6_t *ip6h; 2611628b0c67SMark Fenwick esph_t *esph_ptr, *iv_ptr; 26127c478bd9Sstevel@tonic-gate uint_t af; 26137c478bd9Sstevel@tonic-gate uint8_t *nhp; 26147c478bd9Sstevel@tonic-gate uintptr_t divpoint, datalen, adj, padlen, i, alloclen; 26157c478bd9Sstevel@tonic-gate uintptr_t esplen = sizeof (esph_t); 26167c478bd9Sstevel@tonic-gate uint8_t protocol; 26177c478bd9Sstevel@tonic-gate ipsa_t *assoc; 2618628b0c67SMark Fenwick uint_t iv_len, block_size, mac_len = 0; 26197c478bd9Sstevel@tonic-gate uchar_t *icv_buf; 26207c478bd9Sstevel@tonic-gate udpha_t *udpha; 26217c478bd9Sstevel@tonic-gate boolean_t is_natt = B_FALSE; 2622bd670b35SErik Nordmark netstack_t *ns = ixa->ixa_ipst->ips_netstack; 2623bd670b35SErik Nordmark ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 2624bd670b35SErik Nordmark ipsec_stack_t *ipss = ns->netstack_ipsec; 2625bd670b35SErik Nordmark ill_t *ill = ixa->ixa_nce->nce_ill; 2626bd670b35SErik Nordmark boolean_t need_refrele = B_FALSE; 2627f4b3ec61Sdh155122 2628f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, out_requests); 2629f4b3ec61Sdh155122 26307c478bd9Sstevel@tonic-gate /* 26317c478bd9Sstevel@tonic-gate * <sigh> We have to copy the message here, because TCP (for example) 26327c478bd9Sstevel@tonic-gate * keeps a dupb() of the message lying around for retransmission. 26337c478bd9Sstevel@tonic-gate * Since ESP changes the whole of the datagram, we have to create our 26347c478bd9Sstevel@tonic-gate * own copy lest we clobber TCP's data. Since we have to copy anyway, 26357c478bd9Sstevel@tonic-gate * we might as well make use of msgpullup() and get the mblk into one 26367c478bd9Sstevel@tonic-gate * contiguous piece! 26377c478bd9Sstevel@tonic-gate */ 2638bd670b35SErik Nordmark tailmp = msgpullup(data_mp, -1); 2639bd670b35SErik Nordmark if (tailmp == NULL) { 26407c478bd9Sstevel@tonic-gate esp0dbg(("esp_outbound: msgpullup() failed, " 26417c478bd9Sstevel@tonic-gate "dropping packet.\n")); 2642bd670b35SErik Nordmark ip_drop_packet(data_mp, B_FALSE, ill, 2643f4b3ec61Sdh155122 DROPPER(ipss, ipds_esp_nomem), 2644f4b3ec61Sdh155122 &espstack->esp_dropper); 2645bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards); 2646bd670b35SErik Nordmark return (NULL); 26477c478bd9Sstevel@tonic-gate } 2648bd670b35SErik Nordmark freemsg(data_mp); 2649bd670b35SErik Nordmark data_mp = tailmp; 26507c478bd9Sstevel@tonic-gate 2651bd670b35SErik Nordmark assoc = ixa->ixa_ipsec_esp_sa; 26525d3b8cb7SBill Sommerfeld ASSERT(assoc != NULL); 26535d3b8cb7SBill Sommerfeld 26545d3b8cb7SBill Sommerfeld /* 26555d3b8cb7SBill Sommerfeld * Get the outer IP header in shape to escape this system.. 26565d3b8cb7SBill Sommerfeld */ 2657bd670b35SErik Nordmark if (is_system_labeled() && (assoc->ipsa_otsl != NULL)) { 2658bd670b35SErik Nordmark /* 2659bd670b35SErik Nordmark * Need to update packet with any CIPSO option and update 2660bd670b35SErik Nordmark * ixa_tsl to capture the new label. 2661bd670b35SErik Nordmark * We allocate a separate ixa for that purpose. 2662bd670b35SErik Nordmark */ 2663bd670b35SErik Nordmark ixa = ip_xmit_attr_duplicate(ixa); 2664bd670b35SErik Nordmark if (ixa == NULL) { 2665bd670b35SErik Nordmark ip_drop_packet(data_mp, B_FALSE, ill, 2666bd670b35SErik Nordmark DROPPER(ipss, ipds_esp_nomem), 26675d3b8cb7SBill Sommerfeld &espstack->esp_dropper); 2668bd670b35SErik Nordmark return (NULL); 26695d3b8cb7SBill Sommerfeld } 2670bd670b35SErik Nordmark need_refrele = B_TRUE; 26715d3b8cb7SBill Sommerfeld 2672bd670b35SErik Nordmark label_hold(assoc->ipsa_otsl); 2673bd670b35SErik Nordmark ip_xmit_attr_replace_tsl(ixa, assoc->ipsa_otsl); 2674bd670b35SErik Nordmark 2675bd670b35SErik Nordmark data_mp = sadb_whack_label(data_mp, assoc, ixa, 2676bd670b35SErik Nordmark DROPPER(ipss, ipds_esp_nomem), &espstack->esp_dropper); 2677bd670b35SErik Nordmark if (data_mp == NULL) { 2678bd670b35SErik Nordmark /* Packet dropped by sadb_whack_label */ 2679bd670b35SErik Nordmark ixa_refrele(ixa); 2680bd670b35SErik Nordmark return (NULL); 2681bd670b35SErik Nordmark } 2682bd670b35SErik Nordmark } 26835d3b8cb7SBill Sommerfeld 26847c478bd9Sstevel@tonic-gate /* 26857c478bd9Sstevel@tonic-gate * Reality check.... 26867c478bd9Sstevel@tonic-gate */ 26877c478bd9Sstevel@tonic-gate ipha = (ipha_t *)data_mp->b_rptr; /* So we can call esp_acquire(). */ 26887c478bd9Sstevel@tonic-gate 2689bd670b35SErik Nordmark if (ixa->ixa_flags & IXAF_IS_IPV4) { 2690bd670b35SErik Nordmark ASSERT(IPH_HDR_VERSION(ipha) == IPV4_VERSION); 2691bd670b35SErik Nordmark 26927c478bd9Sstevel@tonic-gate af = AF_INET; 26937c478bd9Sstevel@tonic-gate divpoint = IPH_HDR_LENGTH(ipha); 26947c478bd9Sstevel@tonic-gate datalen = ntohs(ipha->ipha_length) - divpoint; 26957c478bd9Sstevel@tonic-gate nhp = (uint8_t *)&ipha->ipha_protocol; 26967c478bd9Sstevel@tonic-gate } else { 2697bd670b35SErik Nordmark ip_pkt_t ipp; 2698bd670b35SErik Nordmark 2699bd670b35SErik Nordmark ASSERT(IPH_HDR_VERSION(ipha) == IPV6_VERSION); 27007c478bd9Sstevel@tonic-gate 27017c478bd9Sstevel@tonic-gate af = AF_INET6; 27027c478bd9Sstevel@tonic-gate ip6h = (ip6_t *)ipha; 27037c478bd9Sstevel@tonic-gate bzero(&ipp, sizeof (ipp)); 2704bd670b35SErik Nordmark divpoint = ip_find_hdr_v6(data_mp, ip6h, B_FALSE, &ipp, NULL); 27057c478bd9Sstevel@tonic-gate if (ipp.ipp_dstopts != NULL && 27067c478bd9Sstevel@tonic-gate ipp.ipp_dstopts->ip6d_nxt != IPPROTO_ROUTING) { 27077c478bd9Sstevel@tonic-gate /* 27087c478bd9Sstevel@tonic-gate * Destination options are tricky. If we get in here, 27097c478bd9Sstevel@tonic-gate * then we have a terminal header following the 27107c478bd9Sstevel@tonic-gate * destination options. We need to adjust backwards 27117c478bd9Sstevel@tonic-gate * so we insert ESP BEFORE the destination options 27127c478bd9Sstevel@tonic-gate * bag. (So that the dstopts get encrypted!) 27137c478bd9Sstevel@tonic-gate * 27147c478bd9Sstevel@tonic-gate * Since this is for outbound packets only, we know 27157c478bd9Sstevel@tonic-gate * that non-terminal destination options only precede 27167c478bd9Sstevel@tonic-gate * routing headers. 27177c478bd9Sstevel@tonic-gate */ 27187c478bd9Sstevel@tonic-gate divpoint -= ipp.ipp_dstoptslen; 27197c478bd9Sstevel@tonic-gate } 27207c478bd9Sstevel@tonic-gate datalen = ntohs(ip6h->ip6_plen) + sizeof (ip6_t) - divpoint; 27217c478bd9Sstevel@tonic-gate 27227c478bd9Sstevel@tonic-gate if (ipp.ipp_rthdr != NULL) { 27237c478bd9Sstevel@tonic-gate nhp = &ipp.ipp_rthdr->ip6r_nxt; 27247c478bd9Sstevel@tonic-gate } else if (ipp.ipp_hopopts != NULL) { 27257c478bd9Sstevel@tonic-gate nhp = &ipp.ipp_hopopts->ip6h_nxt; 27267c478bd9Sstevel@tonic-gate } else { 27277c478bd9Sstevel@tonic-gate ASSERT(divpoint == sizeof (ip6_t)); 27287c478bd9Sstevel@tonic-gate /* It's probably IP + ESP. */ 27297c478bd9Sstevel@tonic-gate nhp = &ip6h->ip6_nxt; 27307c478bd9Sstevel@tonic-gate } 27317c478bd9Sstevel@tonic-gate } 27327c478bd9Sstevel@tonic-gate 27337c478bd9Sstevel@tonic-gate mac_len = assoc->ipsa_mac_len; 27347c478bd9Sstevel@tonic-gate 27357c478bd9Sstevel@tonic-gate if (assoc->ipsa_flags & IPSA_F_NATT) { 27365d3b8cb7SBill Sommerfeld /* wedge in UDP header */ 27377c478bd9Sstevel@tonic-gate is_natt = B_TRUE; 27387c478bd9Sstevel@tonic-gate esplen += UDPH_SIZE; 27397c478bd9Sstevel@tonic-gate } 27407c478bd9Sstevel@tonic-gate 27417c478bd9Sstevel@tonic-gate /* 27427c478bd9Sstevel@tonic-gate * Set up ESP header and encryption padding for ENCR PI request. 27437c478bd9Sstevel@tonic-gate */ 27447c478bd9Sstevel@tonic-gate 274532350c00Sdanmcd /* Determine the padding length. Pad to 4-bytes for no-encryption. */ 27467c478bd9Sstevel@tonic-gate if (assoc->ipsa_encr_alg != SADB_EALG_NULL) { 274732350c00Sdanmcd iv_len = assoc->ipsa_iv_len; 2748628b0c67SMark Fenwick block_size = assoc->ipsa_datalen; 274932350c00Sdanmcd 275032350c00Sdanmcd /* 2751628b0c67SMark Fenwick * Pad the data to the length of the cipher block size. 275232350c00Sdanmcd * Include the two additional bytes (hence the - 2) for the 275332350c00Sdanmcd * padding length and the next header. Take this into account 275432350c00Sdanmcd * when calculating the actual length of the padding. 275532350c00Sdanmcd */ 275632350c00Sdanmcd ASSERT(ISP2(iv_len)); 2757628b0c67SMark Fenwick padlen = ((unsigned)(block_size - datalen - 2)) & 2758628b0c67SMark Fenwick (block_size - 1); 27597c478bd9Sstevel@tonic-gate } else { 276032350c00Sdanmcd iv_len = 0; 276132350c00Sdanmcd padlen = ((unsigned)(sizeof (uint32_t) - datalen - 2)) & 276232350c00Sdanmcd (sizeof (uint32_t) - 1); 27637c478bd9Sstevel@tonic-gate } 27647c478bd9Sstevel@tonic-gate 27657c478bd9Sstevel@tonic-gate /* Allocate ESP header and IV. */ 27667c478bd9Sstevel@tonic-gate esplen += iv_len; 27677c478bd9Sstevel@tonic-gate 27687c478bd9Sstevel@tonic-gate /* 27697c478bd9Sstevel@tonic-gate * Update association byte-count lifetimes. Don't forget to take 27707c478bd9Sstevel@tonic-gate * into account the padding length and next-header (hence the + 2). 2771a86080f9Sdanmcd * 27727c478bd9Sstevel@tonic-gate * Use the amount of data fed into the "encryption algorithm". This 27737c478bd9Sstevel@tonic-gate * is the IV, the data length, the padding length, and the final two 27747c478bd9Sstevel@tonic-gate * bytes (padlen, and next-header). 27757c478bd9Sstevel@tonic-gate * 27767c478bd9Sstevel@tonic-gate */ 27777c478bd9Sstevel@tonic-gate 2778a86080f9Sdanmcd if (!esp_age_bytes(assoc, datalen + padlen + iv_len + 2, B_FALSE)) { 2779bd670b35SErik Nordmark ip_drop_packet(data_mp, B_FALSE, ill, 2780f4b3ec61Sdh155122 DROPPER(ipss, ipds_esp_bytes_expire), 2781f4b3ec61Sdh155122 &espstack->esp_dropper); 2782bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards); 2783bd670b35SErik Nordmark if (need_refrele) 2784bd670b35SErik Nordmark ixa_refrele(ixa); 2785bd670b35SErik Nordmark return (NULL); 27867c478bd9Sstevel@tonic-gate } 27877c478bd9Sstevel@tonic-gate 27887c478bd9Sstevel@tonic-gate espmp = allocb(esplen, BPRI_HI); 27897c478bd9Sstevel@tonic-gate if (espmp == NULL) { 2790f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, out_discards); 2791f4b3ec61Sdh155122 esp1dbg(espstack, ("esp_outbound: can't allocate espmp.\n")); 2792bd670b35SErik Nordmark ip_drop_packet(data_mp, B_FALSE, ill, 2793f4b3ec61Sdh155122 DROPPER(ipss, ipds_esp_nomem), 2794f4b3ec61Sdh155122 &espstack->esp_dropper); 2795bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards); 2796bd670b35SErik Nordmark if (need_refrele) 2797bd670b35SErik Nordmark ixa_refrele(ixa); 2798bd670b35SErik Nordmark return (NULL); 27997c478bd9Sstevel@tonic-gate } 28007c478bd9Sstevel@tonic-gate espmp->b_wptr += esplen; 2801628b0c67SMark Fenwick esph_ptr = (esph_t *)espmp->b_rptr; 28027c478bd9Sstevel@tonic-gate 28037c478bd9Sstevel@tonic-gate if (is_natt) { 2804f4b3ec61Sdh155122 esp3dbg(espstack, ("esp_outbound: NATT")); 28057c478bd9Sstevel@tonic-gate 28067c478bd9Sstevel@tonic-gate udpha = (udpha_t *)espmp->b_rptr; 2807437220cdSdanmcd udpha->uha_src_port = (assoc->ipsa_local_nat_port != 0) ? 2808437220cdSdanmcd assoc->ipsa_local_nat_port : htons(IPPORT_IKE_NATT); 2809437220cdSdanmcd udpha->uha_dst_port = (assoc->ipsa_remote_nat_port != 0) ? 2810437220cdSdanmcd assoc->ipsa_remote_nat_port : htons(IPPORT_IKE_NATT); 28117c478bd9Sstevel@tonic-gate /* 2812437220cdSdanmcd * Set the checksum to 0, so that the esp_prepare_udp() call 28137c478bd9Sstevel@tonic-gate * can do the right thing. 28147c478bd9Sstevel@tonic-gate */ 28157c478bd9Sstevel@tonic-gate udpha->uha_checksum = 0; 2816628b0c67SMark Fenwick esph_ptr = (esph_t *)(udpha + 1); 28177c478bd9Sstevel@tonic-gate } 28187c478bd9Sstevel@tonic-gate 2819628b0c67SMark Fenwick esph_ptr->esph_spi = assoc->ipsa_spi; 28207c478bd9Sstevel@tonic-gate 2821*1a5e258fSJosef 'Jeff' Sipek esph_ptr->esph_replay = htonl(atomic_inc_32_nv(&assoc->ipsa_replay)); 2822628b0c67SMark Fenwick if (esph_ptr->esph_replay == 0 && assoc->ipsa_replay_wsize != 0) { 28237c478bd9Sstevel@tonic-gate /* 28247c478bd9Sstevel@tonic-gate * XXX We have replay counter wrapping. 28257c478bd9Sstevel@tonic-gate * We probably want to nuke this SA (and its peer). 28267c478bd9Sstevel@tonic-gate */ 28277c478bd9Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, 0, 28287c478bd9Sstevel@tonic-gate SL_ERROR | SL_CONSOLE | SL_WARN, 28297c478bd9Sstevel@tonic-gate "Outbound ESP SA (0x%x, %s) has wrapped sequence.\n", 2830628b0c67SMark Fenwick esph_ptr->esph_spi, assoc->ipsa_dstaddr, af, 2831f4b3ec61Sdh155122 espstack->ipsecesp_netstack); 28327c478bd9Sstevel@tonic-gate 2833f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, out_discards); 28347c478bd9Sstevel@tonic-gate sadb_replay_delete(assoc); 2835bd670b35SErik Nordmark ip_drop_packet(data_mp, B_FALSE, ill, 2836f4b3ec61Sdh155122 DROPPER(ipss, ipds_esp_replay), 2837f4b3ec61Sdh155122 &espstack->esp_dropper); 2838bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards); 2839bd670b35SErik Nordmark if (need_refrele) 2840bd670b35SErik Nordmark ixa_refrele(ixa); 2841bd670b35SErik Nordmark return (NULL); 28427c478bd9Sstevel@tonic-gate } 28437c478bd9Sstevel@tonic-gate 2844628b0c67SMark Fenwick iv_ptr = (esph_ptr + 1); 28457c478bd9Sstevel@tonic-gate /* 2846628b0c67SMark Fenwick * iv_ptr points to the mblk which will contain the IV once we have 2847628b0c67SMark Fenwick * written it there. This mblk will be part of a mblk chain that 2848628b0c67SMark Fenwick * will make up the packet. 2849628b0c67SMark Fenwick * 2850628b0c67SMark Fenwick * For counter mode algorithms, the IV is a 64 bit quantity, it 2851628b0c67SMark Fenwick * must NEVER repeat in the lifetime of the SA, otherwise an 2852628b0c67SMark Fenwick * attacker who had recorded enough packets might be able to 2853628b0c67SMark Fenwick * determine some clear text. 2854628b0c67SMark Fenwick * 2855628b0c67SMark Fenwick * To ensure this does not happen, the IV is stored in the SA and 2856628b0c67SMark Fenwick * incremented for each packet, the IV is then copied into the 2857628b0c67SMark Fenwick * "packet" for transmission to the receiving system. The IV will 2858628b0c67SMark Fenwick * also be copied into the nonce, when the packet is encrypted. 2859628b0c67SMark Fenwick * 2860628b0c67SMark Fenwick * CBC mode algorithms use a random IV for each packet. We do not 2861628b0c67SMark Fenwick * require the highest quality random bits, but for best security 2862628b0c67SMark Fenwick * with CBC mode ciphers, the value must be unlikely to repeat and 2863628b0c67SMark Fenwick * must not be known in advance to an adversary capable of influencing 2864628b0c67SMark Fenwick * the clear text. 28657c478bd9Sstevel@tonic-gate */ 2866628b0c67SMark Fenwick if (!update_iv((uint8_t *)iv_ptr, espstack->esp_pfkey_q, assoc, 2867628b0c67SMark Fenwick espstack)) { 2868bd670b35SErik Nordmark ip_drop_packet(data_mp, B_FALSE, ill, 2869628b0c67SMark Fenwick DROPPER(ipss, ipds_esp_iv_wrap), &espstack->esp_dropper); 2870bd670b35SErik Nordmark if (need_refrele) 2871bd670b35SErik Nordmark ixa_refrele(ixa); 2872bd670b35SErik Nordmark return (NULL); 2873628b0c67SMark Fenwick } 28747c478bd9Sstevel@tonic-gate 28757c478bd9Sstevel@tonic-gate /* Fix the IP header. */ 28767c478bd9Sstevel@tonic-gate alloclen = padlen + 2 + mac_len; 28777c478bd9Sstevel@tonic-gate adj = alloclen + (espmp->b_wptr - espmp->b_rptr); 28787c478bd9Sstevel@tonic-gate 28797c478bd9Sstevel@tonic-gate protocol = *nhp; 28807c478bd9Sstevel@tonic-gate 2881bd670b35SErik Nordmark if (ixa->ixa_flags & IXAF_IS_IPV4) { 28827c478bd9Sstevel@tonic-gate ipha->ipha_length = htons(ntohs(ipha->ipha_length) + adj); 28837c478bd9Sstevel@tonic-gate if (is_natt) { 28847c478bd9Sstevel@tonic-gate *nhp = IPPROTO_UDP; 28857c478bd9Sstevel@tonic-gate udpha->uha_length = htons(ntohs(ipha->ipha_length) - 28867c478bd9Sstevel@tonic-gate IPH_HDR_LENGTH(ipha)); 28877c478bd9Sstevel@tonic-gate } else { 28887c478bd9Sstevel@tonic-gate *nhp = IPPROTO_ESP; 28897c478bd9Sstevel@tonic-gate } 28907c478bd9Sstevel@tonic-gate ipha->ipha_hdr_checksum = 0; 28917c478bd9Sstevel@tonic-gate ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha); 28927c478bd9Sstevel@tonic-gate } else { 28937c478bd9Sstevel@tonic-gate ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) + adj); 28947c478bd9Sstevel@tonic-gate *nhp = IPPROTO_ESP; 28957c478bd9Sstevel@tonic-gate } 28967c478bd9Sstevel@tonic-gate 28977c478bd9Sstevel@tonic-gate /* I've got the two ESP mblks, now insert them. */ 28987c478bd9Sstevel@tonic-gate 2899f4b3ec61Sdh155122 esp2dbg(espstack, ("data_mp before outbound ESP adjustment:\n")); 2900f4b3ec61Sdh155122 esp2dbg(espstack, (dump_msg(data_mp))); 29017c478bd9Sstevel@tonic-gate 2902f4b3ec61Sdh155122 if (!esp_insert_esp(data_mp, espmp, divpoint, espstack)) { 2903f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, out_discards); 29047c478bd9Sstevel@tonic-gate /* NOTE: esp_insert_esp() only fails if there's no memory. */ 2905bd670b35SErik Nordmark ip_drop_packet(data_mp, B_FALSE, ill, 2906f4b3ec61Sdh155122 DROPPER(ipss, ipds_esp_nomem), 2907f4b3ec61Sdh155122 &espstack->esp_dropper); 29087c478bd9Sstevel@tonic-gate freeb(espmp); 2909bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards); 2910bd670b35SErik Nordmark if (need_refrele) 2911bd670b35SErik Nordmark ixa_refrele(ixa); 2912bd670b35SErik Nordmark return (NULL); 29137c478bd9Sstevel@tonic-gate } 29147c478bd9Sstevel@tonic-gate 29157c478bd9Sstevel@tonic-gate /* Append padding (and leave room for ICV). */ 29167c478bd9Sstevel@tonic-gate for (tailmp = data_mp; tailmp->b_cont != NULL; tailmp = tailmp->b_cont) 29177c478bd9Sstevel@tonic-gate ; 29187c478bd9Sstevel@tonic-gate if (tailmp->b_wptr + alloclen > tailmp->b_datap->db_lim) { 29197c478bd9Sstevel@tonic-gate tailmp->b_cont = allocb(alloclen, BPRI_HI); 29207c478bd9Sstevel@tonic-gate if (tailmp->b_cont == NULL) { 2921f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, out_discards); 29227c478bd9Sstevel@tonic-gate esp0dbg(("esp_outbound: Can't allocate tailmp.\n")); 2923bd670b35SErik Nordmark ip_drop_packet(data_mp, B_FALSE, ill, 2924f4b3ec61Sdh155122 DROPPER(ipss, ipds_esp_nomem), 2925f4b3ec61Sdh155122 &espstack->esp_dropper); 2926bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards); 2927bd670b35SErik Nordmark if (need_refrele) 2928bd670b35SErik Nordmark ixa_refrele(ixa); 2929bd670b35SErik Nordmark return (NULL); 29307c478bd9Sstevel@tonic-gate } 29317c478bd9Sstevel@tonic-gate tailmp = tailmp->b_cont; 29327c478bd9Sstevel@tonic-gate } 29337c478bd9Sstevel@tonic-gate 29347c478bd9Sstevel@tonic-gate /* 29357c478bd9Sstevel@tonic-gate * If there's padding, N bytes of padding must be of the form 0x1, 29367c478bd9Sstevel@tonic-gate * 0x2, 0x3... 0xN. 29377c478bd9Sstevel@tonic-gate */ 29387c478bd9Sstevel@tonic-gate for (i = 0; i < padlen; ) { 29397c478bd9Sstevel@tonic-gate i++; 29407c478bd9Sstevel@tonic-gate *tailmp->b_wptr++ = i; 29417c478bd9Sstevel@tonic-gate } 29427c478bd9Sstevel@tonic-gate *tailmp->b_wptr++ = i; 29437c478bd9Sstevel@tonic-gate *tailmp->b_wptr++ = protocol; 29447c478bd9Sstevel@tonic-gate 2945f4b3ec61Sdh155122 esp2dbg(espstack, ("data_Mp before encryption:\n")); 2946f4b3ec61Sdh155122 esp2dbg(espstack, (dump_msg(data_mp))); 29477c478bd9Sstevel@tonic-gate 29487c478bd9Sstevel@tonic-gate /* 29497c478bd9Sstevel@tonic-gate * Okay. I've set up the pre-encryption ESP. Let's do it! 29507c478bd9Sstevel@tonic-gate */ 29517c478bd9Sstevel@tonic-gate 29527c478bd9Sstevel@tonic-gate if (mac_len > 0) { 29537c478bd9Sstevel@tonic-gate ASSERT(tailmp->b_wptr + mac_len <= tailmp->b_datap->db_lim); 29547c478bd9Sstevel@tonic-gate icv_buf = tailmp->b_wptr; 29557c478bd9Sstevel@tonic-gate tailmp->b_wptr += mac_len; 29567c478bd9Sstevel@tonic-gate } else { 29577c478bd9Sstevel@tonic-gate icv_buf = NULL; 29587c478bd9Sstevel@tonic-gate } 29597c478bd9Sstevel@tonic-gate 2960bd670b35SErik Nordmark data_mp = esp_submit_req_outbound(data_mp, ixa, assoc, icv_buf, 2961bd670b35SErik Nordmark datalen + padlen + 2); 2962bd670b35SErik Nordmark if (need_refrele) 2963bd670b35SErik Nordmark ixa_refrele(ixa); 2964bd670b35SErik Nordmark return (data_mp); 29657c478bd9Sstevel@tonic-gate } 29667c478bd9Sstevel@tonic-gate 29677c478bd9Sstevel@tonic-gate /* 29687c478bd9Sstevel@tonic-gate * IP calls this to validate the ICMP errors that 29697c478bd9Sstevel@tonic-gate * we got from the network. 29707c478bd9Sstevel@tonic-gate */ 2971bd670b35SErik Nordmark mblk_t * 2972bd670b35SErik Nordmark ipsecesp_icmp_error(mblk_t *data_mp, ip_recv_attr_t *ira) 29737c478bd9Sstevel@tonic-gate { 2974bd670b35SErik Nordmark netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack; 2975bd670b35SErik Nordmark ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 2976bd670b35SErik Nordmark ipsec_stack_t *ipss = ns->netstack_ipsec; 2977f4b3ec61Sdh155122 29787c478bd9Sstevel@tonic-gate /* 29797c478bd9Sstevel@tonic-gate * Unless we get an entire packet back, this function is useless. 29807c478bd9Sstevel@tonic-gate * Why? 29817c478bd9Sstevel@tonic-gate * 29827c478bd9Sstevel@tonic-gate * 1.) Partial packets are useless, because the "next header" 29837c478bd9Sstevel@tonic-gate * is at the end of the decrypted ESP packet. Without the 29847c478bd9Sstevel@tonic-gate * whole packet, this is useless. 29857c478bd9Sstevel@tonic-gate * 29867c478bd9Sstevel@tonic-gate * 2.) If we every use a stateful cipher, such as a stream or a 29877c478bd9Sstevel@tonic-gate * one-time pad, we can't do anything. 29887c478bd9Sstevel@tonic-gate * 29897c478bd9Sstevel@tonic-gate * Since the chances of us getting an entire packet back are very 29907c478bd9Sstevel@tonic-gate * very small, we discard here. 29917c478bd9Sstevel@tonic-gate */ 2992f4b3ec61Sdh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 2993bd670b35SErik Nordmark ip_drop_packet(data_mp, B_TRUE, ira->ira_ill, 2994f4b3ec61Sdh155122 DROPPER(ipss, ipds_esp_icmp), 2995f4b3ec61Sdh155122 &espstack->esp_dropper); 2996bd670b35SErik Nordmark return (NULL); 29977c478bd9Sstevel@tonic-gate } 29987c478bd9Sstevel@tonic-gate 29997c478bd9Sstevel@tonic-gate /* 30007c478bd9Sstevel@tonic-gate * Construct an SADB_REGISTER message with the current algorithms. 3001628b0c67SMark Fenwick * This function gets called when 'ipsecalgs -s' is run or when 3002628b0c67SMark Fenwick * in.iked (or other KMD) starts. 30037c478bd9Sstevel@tonic-gate */ 30047c478bd9Sstevel@tonic-gate static boolean_t 3005f4b3ec61Sdh155122 esp_register_out(uint32_t sequence, uint32_t pid, uint_t serial, 3006bd670b35SErik Nordmark ipsecesp_stack_t *espstack, cred_t *cr) 30077c478bd9Sstevel@tonic-gate { 30087c478bd9Sstevel@tonic-gate mblk_t *pfkey_msg_mp, *keysock_out_mp; 30097c478bd9Sstevel@tonic-gate sadb_msg_t *samsg; 30107c478bd9Sstevel@tonic-gate sadb_supported_t *sasupp_auth = NULL; 30117c478bd9Sstevel@tonic-gate sadb_supported_t *sasupp_encr = NULL; 30127c478bd9Sstevel@tonic-gate sadb_alg_t *saalg; 30137c478bd9Sstevel@tonic-gate uint_t allocsize = sizeof (*samsg); 30147c478bd9Sstevel@tonic-gate uint_t i, numalgs_snap; 30157c478bd9Sstevel@tonic-gate int current_aalgs; 30167c478bd9Sstevel@tonic-gate ipsec_alginfo_t **authalgs; 30177c478bd9Sstevel@tonic-gate uint_t num_aalgs; 30187c478bd9Sstevel@tonic-gate int current_ealgs; 30197c478bd9Sstevel@tonic-gate ipsec_alginfo_t **encralgs; 30207c478bd9Sstevel@tonic-gate uint_t num_ealgs; 3021f4b3ec61Sdh155122 ipsec_stack_t *ipss = espstack->ipsecesp_netstack->netstack_ipsec; 30225d3b8cb7SBill Sommerfeld sadb_sens_t *sens; 30235d3b8cb7SBill Sommerfeld size_t sens_len = 0; 30245d3b8cb7SBill Sommerfeld sadb_ext_t *nextext; 3025bd670b35SErik Nordmark ts_label_t *sens_tsl = NULL; 30267c478bd9Sstevel@tonic-gate 30277c478bd9Sstevel@tonic-gate /* Allocate the KEYSOCK_OUT. */ 30287c478bd9Sstevel@tonic-gate keysock_out_mp = sadb_keysock_out(serial); 30297c478bd9Sstevel@tonic-gate if (keysock_out_mp == NULL) { 30307c478bd9Sstevel@tonic-gate esp0dbg(("esp_register_out: couldn't allocate mblk.\n")); 30317c478bd9Sstevel@tonic-gate return (B_FALSE); 30327c478bd9Sstevel@tonic-gate } 30337c478bd9Sstevel@tonic-gate 3034bd670b35SErik Nordmark if (is_system_labeled() && (cr != NULL)) { 3035bd670b35SErik Nordmark sens_tsl = crgetlabel(cr); 3036bd670b35SErik Nordmark if (sens_tsl != NULL) { 3037bd670b35SErik Nordmark sens_len = sadb_sens_len_from_label(sens_tsl); 30385d3b8cb7SBill Sommerfeld allocsize += sens_len; 30395d3b8cb7SBill Sommerfeld } 30405d3b8cb7SBill Sommerfeld } 30415d3b8cb7SBill Sommerfeld 30427c478bd9Sstevel@tonic-gate /* 30437c478bd9Sstevel@tonic-gate * Allocate the PF_KEY message that follows KEYSOCK_OUT. 30447c478bd9Sstevel@tonic-gate */ 30457c478bd9Sstevel@tonic-gate 3046f4b3ec61Sdh155122 mutex_enter(&ipss->ipsec_alg_lock); 30477c478bd9Sstevel@tonic-gate /* 30487c478bd9Sstevel@tonic-gate * Fill SADB_REGISTER message's algorithm descriptors. Hold 30497c478bd9Sstevel@tonic-gate * down the lock while filling it. 30507c478bd9Sstevel@tonic-gate * 30517c478bd9Sstevel@tonic-gate * Return only valid algorithms, so the number of algorithms 30527c478bd9Sstevel@tonic-gate * to send up may be less than the number of algorithm entries 30537c478bd9Sstevel@tonic-gate * in the table. 30547c478bd9Sstevel@tonic-gate */ 3055f4b3ec61Sdh155122 authalgs = ipss->ipsec_alglists[IPSEC_ALG_AUTH]; 30567c478bd9Sstevel@tonic-gate for (num_aalgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++) 30577c478bd9Sstevel@tonic-gate if (authalgs[i] != NULL && ALG_VALID(authalgs[i])) 30587c478bd9Sstevel@tonic-gate num_aalgs++; 30597c478bd9Sstevel@tonic-gate 30607c478bd9Sstevel@tonic-gate if (num_aalgs != 0) { 30617c478bd9Sstevel@tonic-gate allocsize += (num_aalgs * sizeof (*saalg)); 30627c478bd9Sstevel@tonic-gate allocsize += sizeof (*sasupp_auth); 30637c478bd9Sstevel@tonic-gate } 3064f4b3ec61Sdh155122 encralgs = ipss->ipsec_alglists[IPSEC_ALG_ENCR]; 30657c478bd9Sstevel@tonic-gate for (num_ealgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++) 30667c478bd9Sstevel@tonic-gate if (encralgs[i] != NULL && ALG_VALID(encralgs[i])) 30677c478bd9Sstevel@tonic-gate num_ealgs++; 30687c478bd9Sstevel@tonic-gate 30697c478bd9Sstevel@tonic-gate if (num_ealgs != 0) { 30707c478bd9Sstevel@tonic-gate allocsize += (num_ealgs * sizeof (*saalg)); 30717c478bd9Sstevel@tonic-gate allocsize += sizeof (*sasupp_encr); 30727c478bd9Sstevel@tonic-gate } 30737c478bd9Sstevel@tonic-gate keysock_out_mp->b_cont = allocb(allocsize, BPRI_HI); 30747c478bd9Sstevel@tonic-gate if (keysock_out_mp->b_cont == NULL) { 3075f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 30767c478bd9Sstevel@tonic-gate freemsg(keysock_out_mp); 30777c478bd9Sstevel@tonic-gate return (B_FALSE); 30787c478bd9Sstevel@tonic-gate } 30797c478bd9Sstevel@tonic-gate pfkey_msg_mp = keysock_out_mp->b_cont; 30807c478bd9Sstevel@tonic-gate pfkey_msg_mp->b_wptr += allocsize; 30815d3b8cb7SBill Sommerfeld 30825d3b8cb7SBill Sommerfeld nextext = (sadb_ext_t *)(pfkey_msg_mp->b_rptr + sizeof (*samsg)); 30835d3b8cb7SBill Sommerfeld 30847c478bd9Sstevel@tonic-gate if (num_aalgs != 0) { 30855d3b8cb7SBill Sommerfeld sasupp_auth = (sadb_supported_t *)nextext; 30867c478bd9Sstevel@tonic-gate saalg = (sadb_alg_t *)(sasupp_auth + 1); 30877c478bd9Sstevel@tonic-gate 30887c478bd9Sstevel@tonic-gate ASSERT(((ulong_t)saalg & 0x7) == 0); 30897c478bd9Sstevel@tonic-gate 30907c478bd9Sstevel@tonic-gate numalgs_snap = 0; 30917c478bd9Sstevel@tonic-gate for (i = 0; 3092f4b3ec61Sdh155122 ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_aalgs)); 3093f4b3ec61Sdh155122 i++) { 30947c478bd9Sstevel@tonic-gate if (authalgs[i] == NULL || !ALG_VALID(authalgs[i])) 30957c478bd9Sstevel@tonic-gate continue; 30967c478bd9Sstevel@tonic-gate 30977c478bd9Sstevel@tonic-gate saalg->sadb_alg_id = authalgs[i]->alg_id; 30987c478bd9Sstevel@tonic-gate saalg->sadb_alg_ivlen = 0; 30997c478bd9Sstevel@tonic-gate saalg->sadb_alg_minbits = authalgs[i]->alg_ef_minbits; 31007c478bd9Sstevel@tonic-gate saalg->sadb_alg_maxbits = authalgs[i]->alg_ef_maxbits; 31017c478bd9Sstevel@tonic-gate saalg->sadb_x_alg_increment = 31027c478bd9Sstevel@tonic-gate authalgs[i]->alg_increment; 3103628b0c67SMark Fenwick saalg->sadb_x_alg_saltbits = SADB_8TO1( 3104628b0c67SMark Fenwick authalgs[i]->alg_saltlen); 31057c478bd9Sstevel@tonic-gate numalgs_snap++; 31067c478bd9Sstevel@tonic-gate saalg++; 31077c478bd9Sstevel@tonic-gate } 31087c478bd9Sstevel@tonic-gate ASSERT(numalgs_snap == num_aalgs); 31097c478bd9Sstevel@tonic-gate #ifdef DEBUG 31107c478bd9Sstevel@tonic-gate /* 31117c478bd9Sstevel@tonic-gate * Reality check to make sure I snagged all of the 31127c478bd9Sstevel@tonic-gate * algorithms. 31137c478bd9Sstevel@tonic-gate */ 31147c478bd9Sstevel@tonic-gate for (; i < IPSEC_MAX_ALGS; i++) { 31157c478bd9Sstevel@tonic-gate if (authalgs[i] != NULL && ALG_VALID(authalgs[i])) { 31167c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "esp_register_out()! " 31177c478bd9Sstevel@tonic-gate "Missed aalg #%d.\n", i); 31187c478bd9Sstevel@tonic-gate } 31197c478bd9Sstevel@tonic-gate } 31207c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 31215d3b8cb7SBill Sommerfeld nextext = (sadb_ext_t *)saalg; 31227c478bd9Sstevel@tonic-gate } 31237c478bd9Sstevel@tonic-gate 31247c478bd9Sstevel@tonic-gate if (num_ealgs != 0) { 31255d3b8cb7SBill Sommerfeld sasupp_encr = (sadb_supported_t *)nextext; 31267c478bd9Sstevel@tonic-gate saalg = (sadb_alg_t *)(sasupp_encr + 1); 31277c478bd9Sstevel@tonic-gate 31287c478bd9Sstevel@tonic-gate numalgs_snap = 0; 31297c478bd9Sstevel@tonic-gate for (i = 0; 31307c478bd9Sstevel@tonic-gate ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_ealgs)); i++) { 31317c478bd9Sstevel@tonic-gate if (encralgs[i] == NULL || !ALG_VALID(encralgs[i])) 31327c478bd9Sstevel@tonic-gate continue; 31337c478bd9Sstevel@tonic-gate saalg->sadb_alg_id = encralgs[i]->alg_id; 3134628b0c67SMark Fenwick saalg->sadb_alg_ivlen = encralgs[i]->alg_ivlen; 31357c478bd9Sstevel@tonic-gate saalg->sadb_alg_minbits = encralgs[i]->alg_ef_minbits; 31367c478bd9Sstevel@tonic-gate saalg->sadb_alg_maxbits = encralgs[i]->alg_ef_maxbits; 3137628b0c67SMark Fenwick /* 3138628b0c67SMark Fenwick * We could advertise the ICV length, except there 3139628b0c67SMark Fenwick * is not a value in sadb_x_algb to do this. 3140628b0c67SMark Fenwick * saalg->sadb_alg_maclen = encralgs[i]->alg_maclen; 3141628b0c67SMark Fenwick */ 31427c478bd9Sstevel@tonic-gate saalg->sadb_x_alg_increment = 31437c478bd9Sstevel@tonic-gate encralgs[i]->alg_increment; 3144628b0c67SMark Fenwick saalg->sadb_x_alg_saltbits = 3145628b0c67SMark Fenwick SADB_8TO1(encralgs[i]->alg_saltlen); 3146628b0c67SMark Fenwick 31477c478bd9Sstevel@tonic-gate numalgs_snap++; 31487c478bd9Sstevel@tonic-gate saalg++; 31497c478bd9Sstevel@tonic-gate } 31507c478bd9Sstevel@tonic-gate ASSERT(numalgs_snap == num_ealgs); 31517c478bd9Sstevel@tonic-gate #ifdef DEBUG 31527c478bd9Sstevel@tonic-gate /* 31537c478bd9Sstevel@tonic-gate * Reality check to make sure I snagged all of the 31547c478bd9Sstevel@tonic-gate * algorithms. 31557c478bd9Sstevel@tonic-gate */ 31567c478bd9Sstevel@tonic-gate for (; i < IPSEC_MAX_ALGS; i++) { 31577c478bd9Sstevel@tonic-gate if (encralgs[i] != NULL && ALG_VALID(encralgs[i])) { 31587c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "esp_register_out()! " 31597c478bd9Sstevel@tonic-gate "Missed ealg #%d.\n", i); 31607c478bd9Sstevel@tonic-gate } 31617c478bd9Sstevel@tonic-gate } 31627c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 31635d3b8cb7SBill Sommerfeld nextext = (sadb_ext_t *)saalg; 31647c478bd9Sstevel@tonic-gate } 31657c478bd9Sstevel@tonic-gate 31667c478bd9Sstevel@tonic-gate current_aalgs = num_aalgs; 31677c478bd9Sstevel@tonic-gate current_ealgs = num_ealgs; 31687c478bd9Sstevel@tonic-gate 3169f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 31707c478bd9Sstevel@tonic-gate 3171bd670b35SErik Nordmark if (sens_tsl != NULL) { 31725d3b8cb7SBill Sommerfeld sens = (sadb_sens_t *)nextext; 3173bd670b35SErik Nordmark sadb_sens_from_label(sens, SADB_EXT_SENSITIVITY, 3174bd670b35SErik Nordmark sens_tsl, sens_len); 31755d3b8cb7SBill Sommerfeld 31765d3b8cb7SBill Sommerfeld nextext = (sadb_ext_t *)(((uint8_t *)sens) + sens_len); 31775d3b8cb7SBill Sommerfeld } 31785d3b8cb7SBill Sommerfeld 31797c478bd9Sstevel@tonic-gate /* Now fill the rest of the SADB_REGISTER message. */ 31807c478bd9Sstevel@tonic-gate 31817c478bd9Sstevel@tonic-gate samsg = (sadb_msg_t *)pfkey_msg_mp->b_rptr; 31827c478bd9Sstevel@tonic-gate samsg->sadb_msg_version = PF_KEY_V2; 31837c478bd9Sstevel@tonic-gate samsg->sadb_msg_type = SADB_REGISTER; 31847c478bd9Sstevel@tonic-gate samsg->sadb_msg_errno = 0; 31857c478bd9Sstevel@tonic-gate samsg->sadb_msg_satype = SADB_SATYPE_ESP; 31867c478bd9Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(allocsize); 31877c478bd9Sstevel@tonic-gate samsg->sadb_msg_reserved = 0; 31887c478bd9Sstevel@tonic-gate /* 31897c478bd9Sstevel@tonic-gate * Assume caller has sufficient sequence/pid number info. If it's one 31907c478bd9Sstevel@tonic-gate * from me over a new alg., I could give two hoots about sequence. 31917c478bd9Sstevel@tonic-gate */ 31927c478bd9Sstevel@tonic-gate samsg->sadb_msg_seq = sequence; 31937c478bd9Sstevel@tonic-gate samsg->sadb_msg_pid = pid; 31947c478bd9Sstevel@tonic-gate 31957c478bd9Sstevel@tonic-gate if (sasupp_auth != NULL) { 3196437220cdSdanmcd sasupp_auth->sadb_supported_len = SADB_8TO64( 3197437220cdSdanmcd sizeof (*sasupp_auth) + sizeof (*saalg) * current_aalgs); 31987c478bd9Sstevel@tonic-gate sasupp_auth->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; 31997c478bd9Sstevel@tonic-gate sasupp_auth->sadb_supported_reserved = 0; 32007c478bd9Sstevel@tonic-gate } 32017c478bd9Sstevel@tonic-gate 32027c478bd9Sstevel@tonic-gate if (sasupp_encr != NULL) { 3203437220cdSdanmcd sasupp_encr->sadb_supported_len = SADB_8TO64( 3204437220cdSdanmcd sizeof (*sasupp_encr) + sizeof (*saalg) * current_ealgs); 32057c478bd9Sstevel@tonic-gate sasupp_encr->sadb_supported_exttype = 32067c478bd9Sstevel@tonic-gate SADB_EXT_SUPPORTED_ENCRYPT; 32077c478bd9Sstevel@tonic-gate sasupp_encr->sadb_supported_reserved = 0; 32087c478bd9Sstevel@tonic-gate } 32097c478bd9Sstevel@tonic-gate 3210f4b3ec61Sdh155122 if (espstack->esp_pfkey_q != NULL) 3211f4b3ec61Sdh155122 putnext(espstack->esp_pfkey_q, keysock_out_mp); 32127c478bd9Sstevel@tonic-gate else { 32137c478bd9Sstevel@tonic-gate freemsg(keysock_out_mp); 32147c478bd9Sstevel@tonic-gate return (B_FALSE); 32157c478bd9Sstevel@tonic-gate } 32167c478bd9Sstevel@tonic-gate 32177c478bd9Sstevel@tonic-gate return (B_TRUE); 32187c478bd9Sstevel@tonic-gate } 32197c478bd9Sstevel@tonic-gate 32207c478bd9Sstevel@tonic-gate /* 32217c478bd9Sstevel@tonic-gate * Invoked when the algorithm table changes. Causes SADB_REGISTER 32227c478bd9Sstevel@tonic-gate * messages continaining the current list of algorithms to be 32237c478bd9Sstevel@tonic-gate * sent up to the ESP listeners. 32247c478bd9Sstevel@tonic-gate */ 32257c478bd9Sstevel@tonic-gate void 3226f4b3ec61Sdh155122 ipsecesp_algs_changed(netstack_t *ns) 32277c478bd9Sstevel@tonic-gate { 3228f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 3229f4b3ec61Sdh155122 32307c478bd9Sstevel@tonic-gate /* 32317c478bd9Sstevel@tonic-gate * Time to send a PF_KEY SADB_REGISTER message to ESP listeners 32327c478bd9Sstevel@tonic-gate * everywhere. (The function itself checks for NULL esp_pfkey_q.) 32337c478bd9Sstevel@tonic-gate */ 32345d3b8cb7SBill Sommerfeld (void) esp_register_out(0, 0, 0, espstack, NULL); 32357c478bd9Sstevel@tonic-gate } 32367c478bd9Sstevel@tonic-gate 32377c478bd9Sstevel@tonic-gate /* 323873184bc7SDan McDonald * Stub function that taskq_dispatch() invokes to take the mblk (in arg) 3239bd670b35SErik Nordmark * and send() it into ESP and IP again. 32407c478bd9Sstevel@tonic-gate */ 32417c478bd9Sstevel@tonic-gate static void 32427c478bd9Sstevel@tonic-gate inbound_task(void *arg) 32437c478bd9Sstevel@tonic-gate { 32447c478bd9Sstevel@tonic-gate mblk_t *mp = (mblk_t *)arg; 3245bd670b35SErik Nordmark mblk_t *async_mp; 3246bd670b35SErik Nordmark ip_recv_attr_t iras; 32477c478bd9Sstevel@tonic-gate 3248bd670b35SErik Nordmark async_mp = mp; 3249bd670b35SErik Nordmark mp = async_mp->b_cont; 3250bd670b35SErik Nordmark async_mp->b_cont = NULL; 3251bd670b35SErik Nordmark if (!ip_recv_attr_from_mblk(async_mp, &iras)) { 3252bd670b35SErik Nordmark /* The ill or ip_stack_t disappeared on us */ 3253bd670b35SErik Nordmark ip_drop_input("ip_recv_attr_from_mblk", mp, NULL); 325473184bc7SDan McDonald freemsg(mp); 3255bd670b35SErik Nordmark goto done; 325673184bc7SDan McDonald } 325773184bc7SDan McDonald 3258bd670b35SErik Nordmark esp_inbound_restart(mp, &iras); 3259bd670b35SErik Nordmark done: 3260bd670b35SErik Nordmark ira_cleanup(&iras, B_TRUE); 3261bd670b35SErik Nordmark } 3262bd670b35SErik Nordmark 3263bd670b35SErik Nordmark /* 3264bd670b35SErik Nordmark * Restart ESP after the SA has been added. 3265bd670b35SErik Nordmark */ 3266bd670b35SErik Nordmark static void 3267bd670b35SErik Nordmark esp_inbound_restart(mblk_t *mp, ip_recv_attr_t *ira) 3268bd670b35SErik Nordmark { 3269bd670b35SErik Nordmark esph_t *esph; 3270bd670b35SErik Nordmark netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack; 3271bd670b35SErik Nordmark ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 327273184bc7SDan McDonald 3273f4b3ec61Sdh155122 esp2dbg(espstack, ("in ESP inbound_task")); 3274f4b3ec61Sdh155122 ASSERT(espstack != NULL); 32757c478bd9Sstevel@tonic-gate 3276bd670b35SErik Nordmark mp = ipsec_inbound_esp_sa(mp, ira, &esph); 3277bd670b35SErik Nordmark if (mp == NULL) 3278bd670b35SErik Nordmark return; 3279bd670b35SErik Nordmark 3280bd670b35SErik Nordmark ASSERT(esph != NULL); 3281bd670b35SErik Nordmark ASSERT(ira->ira_flags & IRAF_IPSEC_SECURE); 3282bd670b35SErik Nordmark ASSERT(ira->ira_ipsec_esp_sa != NULL); 3283bd670b35SErik Nordmark 3284bd670b35SErik Nordmark mp = ira->ira_ipsec_esp_sa->ipsa_input_func(mp, esph, ira); 3285bd670b35SErik Nordmark if (mp == NULL) { 3286bd670b35SErik Nordmark /* 3287bd670b35SErik Nordmark * Either it failed or is pending. In the former case 3288bd670b35SErik Nordmark * ipIfStatsInDiscards was increased. 3289bd670b35SErik Nordmark */ 3290bd670b35SErik Nordmark return; 32917c478bd9Sstevel@tonic-gate } 3292bd670b35SErik Nordmark 3293bd670b35SErik Nordmark ip_input_post_ipsec(mp, ira); 329473184bc7SDan McDonald } 32957c478bd9Sstevel@tonic-gate 32967c478bd9Sstevel@tonic-gate /* 32977c478bd9Sstevel@tonic-gate * Now that weak-key passed, actually ADD the security association, and 32987c478bd9Sstevel@tonic-gate * send back a reply ADD message. 32997c478bd9Sstevel@tonic-gate */ 33007c478bd9Sstevel@tonic-gate static int 33018810c16bSdanmcd esp_add_sa_finish(mblk_t *mp, sadb_msg_t *samsg, keysock_in_t *ksi, 3302f4b3ec61Sdh155122 int *diagnostic, ipsecesp_stack_t *espstack) 33037c478bd9Sstevel@tonic-gate { 33045d3b8cb7SBill Sommerfeld isaf_t *primary = NULL, *secondary; 33055d3b8cb7SBill Sommerfeld boolean_t clone = B_FALSE, is_inbound = B_FALSE; 33067c478bd9Sstevel@tonic-gate ipsa_t *larval = NULL; 33077c478bd9Sstevel@tonic-gate ipsacq_t *acqrec; 33087c478bd9Sstevel@tonic-gate iacqf_t *acq_bucket; 33097c478bd9Sstevel@tonic-gate mblk_t *acq_msgs = NULL; 33107c478bd9Sstevel@tonic-gate int rc; 33117c478bd9Sstevel@tonic-gate mblk_t *lpkt; 33125d3b8cb7SBill Sommerfeld int error; 33135d3b8cb7SBill Sommerfeld ipsa_query_t sq; 3314f4b3ec61Sdh155122 ipsec_stack_t *ipss = espstack->ipsecesp_netstack->netstack_ipsec; 33157c478bd9Sstevel@tonic-gate 33167c478bd9Sstevel@tonic-gate /* 33177c478bd9Sstevel@tonic-gate * Locate the appropriate table(s). 33187c478bd9Sstevel@tonic-gate */ 33195d3b8cb7SBill Sommerfeld sq.spp = &espstack->esp_sadb; /* XXX */ 33205d3b8cb7SBill Sommerfeld error = sadb_form_query(ksi, IPSA_Q_SA|IPSA_Q_DST, 33215d3b8cb7SBill Sommerfeld IPSA_Q_SA|IPSA_Q_DST|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND, 33225d3b8cb7SBill Sommerfeld &sq, diagnostic); 33235d3b8cb7SBill Sommerfeld if (error) 33245d3b8cb7SBill Sommerfeld return (error); 332507b56925Ssommerfe 332638d95a78Smarkfen /* 332738d95a78Smarkfen * Use the direction flags provided by the KMD to determine 332838d95a78Smarkfen * if the inbound or outbound table should be the primary 332938d95a78Smarkfen * for this SA. If these flags were absent then make this 333038d95a78Smarkfen * decision based on the addresses. 333138d95a78Smarkfen */ 33325d3b8cb7SBill Sommerfeld if (sq.assoc->sadb_sa_flags & IPSA_F_INBOUND) { 33335d3b8cb7SBill Sommerfeld primary = sq.inbound; 33345d3b8cb7SBill Sommerfeld secondary = sq.outbound; 333538d95a78Smarkfen is_inbound = B_TRUE; 33365d3b8cb7SBill Sommerfeld if (sq.assoc->sadb_sa_flags & IPSA_F_OUTBOUND) 333738d95a78Smarkfen clone = B_TRUE; 33385d3b8cb7SBill Sommerfeld } else if (sq.assoc->sadb_sa_flags & IPSA_F_OUTBOUND) { 33395d3b8cb7SBill Sommerfeld primary = sq.outbound; 33405d3b8cb7SBill Sommerfeld secondary = sq.inbound; 334138d95a78Smarkfen } 334238d95a78Smarkfen 334338d95a78Smarkfen if (primary == NULL) { 334438d95a78Smarkfen /* 334538d95a78Smarkfen * The KMD did not set a direction flag, determine which 334638d95a78Smarkfen * table to insert the SA into based on addresses. 334738d95a78Smarkfen */ 33487c478bd9Sstevel@tonic-gate switch (ksi->ks_in_dsttype) { 33497c478bd9Sstevel@tonic-gate case KS_IN_ADDR_MBCAST: 33507c478bd9Sstevel@tonic-gate clone = B_TRUE; /* All mcast SAs can be bidirectional */ 33515d3b8cb7SBill Sommerfeld sq.assoc->sadb_sa_flags |= IPSA_F_OUTBOUND; 33527c478bd9Sstevel@tonic-gate /* FALLTHRU */ 33537c478bd9Sstevel@tonic-gate /* 33547c478bd9Sstevel@tonic-gate * If the source address is either one of mine, or unspecified 33557c478bd9Sstevel@tonic-gate * (which is best summed up by saying "not 'not mine'"), 33567c478bd9Sstevel@tonic-gate * then the association is potentially bi-directional, 33577c478bd9Sstevel@tonic-gate * in that it can be used for inbound traffic and outbound 33587c478bd9Sstevel@tonic-gate * traffic. The best example of such an SA is a multicast 33597c478bd9Sstevel@tonic-gate * SA (which allows me to receive the outbound traffic). 33607c478bd9Sstevel@tonic-gate */ 336138d95a78Smarkfen case KS_IN_ADDR_ME: 33625d3b8cb7SBill Sommerfeld sq.assoc->sadb_sa_flags |= IPSA_F_INBOUND; 33635d3b8cb7SBill Sommerfeld primary = sq.inbound; 33645d3b8cb7SBill Sommerfeld secondary = sq.outbound; 33657c478bd9Sstevel@tonic-gate if (ksi->ks_in_srctype != KS_IN_ADDR_NOTME) 33667c478bd9Sstevel@tonic-gate clone = B_TRUE; 33677c478bd9Sstevel@tonic-gate is_inbound = B_TRUE; 33687c478bd9Sstevel@tonic-gate break; 33697c478bd9Sstevel@tonic-gate /* 33707c478bd9Sstevel@tonic-gate * If the source address literally not mine (either 33717c478bd9Sstevel@tonic-gate * unspecified or not mine), then this SA may have an 33727c478bd9Sstevel@tonic-gate * address that WILL be mine after some configuration. 33737c478bd9Sstevel@tonic-gate * We pay the price for this by making it a bi-directional 33747c478bd9Sstevel@tonic-gate * SA. 33757c478bd9Sstevel@tonic-gate */ 337638d95a78Smarkfen case KS_IN_ADDR_NOTME: 33775d3b8cb7SBill Sommerfeld sq.assoc->sadb_sa_flags |= IPSA_F_OUTBOUND; 33785d3b8cb7SBill Sommerfeld primary = sq.outbound; 33795d3b8cb7SBill Sommerfeld secondary = sq.inbound; 338038d95a78Smarkfen if (ksi->ks_in_srctype != KS_IN_ADDR_ME) { 33815d3b8cb7SBill Sommerfeld sq.assoc->sadb_sa_flags |= IPSA_F_INBOUND; 33827c478bd9Sstevel@tonic-gate clone = B_TRUE; 338338d95a78Smarkfen } 33847c478bd9Sstevel@tonic-gate break; 33857c478bd9Sstevel@tonic-gate default: 33868810c16bSdanmcd *diagnostic = SADB_X_DIAGNOSTIC_BAD_DST; 33877c478bd9Sstevel@tonic-gate return (EINVAL); 33887c478bd9Sstevel@tonic-gate } 338938d95a78Smarkfen } 33907c478bd9Sstevel@tonic-gate 33917c478bd9Sstevel@tonic-gate /* 33927c478bd9Sstevel@tonic-gate * Find a ACQUIRE list entry if possible. If we've added an SA that 33937c478bd9Sstevel@tonic-gate * suits the needs of an ACQUIRE list entry, we can eliminate the 33947c478bd9Sstevel@tonic-gate * ACQUIRE list entry and transmit the enqueued packets. Use the 33957c478bd9Sstevel@tonic-gate * high-bit of the sequence number to queue it. Key off destination 33967c478bd9Sstevel@tonic-gate * addr, and change acqrec's state. 33977c478bd9Sstevel@tonic-gate */ 33987c478bd9Sstevel@tonic-gate 33997c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_seq & IACQF_LOWEST_SEQ) { 34005d3b8cb7SBill Sommerfeld acq_bucket = &(sq.sp->sdb_acq[sq.outhash]); 34017c478bd9Sstevel@tonic-gate mutex_enter(&acq_bucket->iacqf_lock); 34027c478bd9Sstevel@tonic-gate for (acqrec = acq_bucket->iacqf_ipsacq; acqrec != NULL; 34037c478bd9Sstevel@tonic-gate acqrec = acqrec->ipsacq_next) { 34047c478bd9Sstevel@tonic-gate mutex_enter(&acqrec->ipsacq_lock); 34057c478bd9Sstevel@tonic-gate /* 34067c478bd9Sstevel@tonic-gate * Q: I only check sequence. Should I check dst? 34077c478bd9Sstevel@tonic-gate * A: Yes, check dest because those are the packets 34087c478bd9Sstevel@tonic-gate * that are queued up. 34097c478bd9Sstevel@tonic-gate */ 34107c478bd9Sstevel@tonic-gate if (acqrec->ipsacq_seq == samsg->sadb_msg_seq && 34115d3b8cb7SBill Sommerfeld IPSA_ARE_ADDR_EQUAL(sq.dstaddr, 34127c478bd9Sstevel@tonic-gate acqrec->ipsacq_dstaddr, acqrec->ipsacq_addrfam)) 34137c478bd9Sstevel@tonic-gate break; 34147c478bd9Sstevel@tonic-gate mutex_exit(&acqrec->ipsacq_lock); 34157c478bd9Sstevel@tonic-gate } 34167c478bd9Sstevel@tonic-gate if (acqrec != NULL) { 34177c478bd9Sstevel@tonic-gate /* 34187c478bd9Sstevel@tonic-gate * AHA! I found an ACQUIRE record for this SA. 34197c478bd9Sstevel@tonic-gate * Grab the msg list, and free the acquire record. 34207c478bd9Sstevel@tonic-gate * I already am holding the lock for this record, 34217c478bd9Sstevel@tonic-gate * so all I have to do is free it. 34227c478bd9Sstevel@tonic-gate */ 34237c478bd9Sstevel@tonic-gate acq_msgs = acqrec->ipsacq_mp; 34247c478bd9Sstevel@tonic-gate acqrec->ipsacq_mp = NULL; 34257c478bd9Sstevel@tonic-gate mutex_exit(&acqrec->ipsacq_lock); 3426f4b3ec61Sdh155122 sadb_destroy_acquire(acqrec, 3427f4b3ec61Sdh155122 espstack->ipsecesp_netstack); 34287c478bd9Sstevel@tonic-gate } 34297c478bd9Sstevel@tonic-gate mutex_exit(&acq_bucket->iacqf_lock); 34307c478bd9Sstevel@tonic-gate } 34317c478bd9Sstevel@tonic-gate 34327c478bd9Sstevel@tonic-gate /* 34337c478bd9Sstevel@tonic-gate * Find PF_KEY message, and see if I'm an update. If so, find entry 34347c478bd9Sstevel@tonic-gate * in larval list (if there). 34357c478bd9Sstevel@tonic-gate */ 34367c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_UPDATE) { 34375d3b8cb7SBill Sommerfeld mutex_enter(&sq.inbound->isaf_lock); 34385d3b8cb7SBill Sommerfeld larval = ipsec_getassocbyspi(sq.inbound, sq.assoc->sadb_sa_spi, 34395d3b8cb7SBill Sommerfeld ALL_ZEROES_PTR, sq.dstaddr, sq.dst->sin_family); 34405d3b8cb7SBill Sommerfeld mutex_exit(&sq.inbound->isaf_lock); 34417c478bd9Sstevel@tonic-gate 344272bd9b6bSdanmcd if ((larval == NULL) || 344372bd9b6bSdanmcd (larval->ipsa_state != IPSA_STATE_LARVAL)) { 344438d95a78Smarkfen *diagnostic = SADB_X_DIAGNOSTIC_SA_NOTFOUND; 344572bd9b6bSdanmcd if (larval != NULL) { 344672bd9b6bSdanmcd IPSA_REFRELE(larval); 344772bd9b6bSdanmcd } 34487c478bd9Sstevel@tonic-gate esp0dbg(("Larval update, but larval disappeared.\n")); 34497c478bd9Sstevel@tonic-gate return (ESRCH); 34507c478bd9Sstevel@tonic-gate } /* Else sadb_common_add unlinks it for me! */ 34517c478bd9Sstevel@tonic-gate } 34527c478bd9Sstevel@tonic-gate 3453930af642SDan McDonald if (larval != NULL) { 3454930af642SDan McDonald /* 3455930af642SDan McDonald * Hold again, because sadb_common_add() consumes a reference, 3456930af642SDan McDonald * and we don't want to clear_lpkt() without a reference. 3457930af642SDan McDonald */ 3458930af642SDan McDonald IPSA_REFHOLD(larval); 3459930af642SDan McDonald } 34607c478bd9Sstevel@tonic-gate 3461bd670b35SErik Nordmark rc = sadb_common_add(espstack->esp_pfkey_q, 3462f4b3ec61Sdh155122 mp, samsg, ksi, primary, secondary, larval, clone, is_inbound, 346338d95a78Smarkfen diagnostic, espstack->ipsecesp_netstack, &espstack->esp_sadb); 34647c478bd9Sstevel@tonic-gate 3465930af642SDan McDonald if (larval != NULL) { 3466bd670b35SErik Nordmark if (rc == 0) { 3467930af642SDan McDonald lpkt = sadb_clear_lpkt(larval); 3468930af642SDan McDonald if (lpkt != NULL) { 3469bd670b35SErik Nordmark rc = !taskq_dispatch(esp_taskq, inbound_task, 3470bd670b35SErik Nordmark lpkt, TQ_NOSLEEP); 3471bd670b35SErik Nordmark } 34727c478bd9Sstevel@tonic-gate } 3473930af642SDan McDonald IPSA_REFRELE(larval); 3474bd670b35SErik Nordmark } 34757c478bd9Sstevel@tonic-gate 34767c478bd9Sstevel@tonic-gate /* 34777c478bd9Sstevel@tonic-gate * How much more stack will I create with all of these 34787c478bd9Sstevel@tonic-gate * esp_outbound() calls? 34797c478bd9Sstevel@tonic-gate */ 34807c478bd9Sstevel@tonic-gate 3481bd670b35SErik Nordmark /* Handle the packets queued waiting for the SA */ 34827c478bd9Sstevel@tonic-gate while (acq_msgs != NULL) { 3483bd670b35SErik Nordmark mblk_t *asyncmp; 3484bd670b35SErik Nordmark mblk_t *data_mp; 3485bd670b35SErik Nordmark ip_xmit_attr_t ixas; 3486bd670b35SErik Nordmark ill_t *ill; 34877c478bd9Sstevel@tonic-gate 3488bd670b35SErik Nordmark asyncmp = acq_msgs; 34897c478bd9Sstevel@tonic-gate acq_msgs = acq_msgs->b_next; 3490bd670b35SErik Nordmark asyncmp->b_next = NULL; 34917c478bd9Sstevel@tonic-gate 3492bd670b35SErik Nordmark /* 3493bd670b35SErik Nordmark * Extract the ip_xmit_attr_t from the first mblk. 3494bd670b35SErik Nordmark * Verifies that the netstack and ill is still around; could 3495bd670b35SErik Nordmark * have vanished while iked was doing its work. 3496bd670b35SErik Nordmark * On succesful return we have a nce_t and the ill/ipst can't 3497bd670b35SErik Nordmark * disappear until we do the nce_refrele in ixa_cleanup. 3498bd670b35SErik Nordmark */ 3499bd670b35SErik Nordmark data_mp = asyncmp->b_cont; 3500bd670b35SErik Nordmark asyncmp->b_cont = NULL; 3501bd670b35SErik Nordmark if (!ip_xmit_attr_from_mblk(asyncmp, &ixas)) { 3502f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, out_discards); 3503bd670b35SErik Nordmark ip_drop_packet(data_mp, B_FALSE, NULL, 3504f4b3ec61Sdh155122 DROPPER(ipss, ipds_sadb_acquire_timeout), 3505f4b3ec61Sdh155122 &espstack->esp_dropper); 3506bd670b35SErik Nordmark } else if (rc != 0) { 3507bd670b35SErik Nordmark ill = ixas.ixa_nce->nce_ill; 3508bd670b35SErik Nordmark ESP_BUMP_STAT(espstack, out_discards); 3509bd670b35SErik Nordmark ip_drop_packet(data_mp, B_FALSE, ill, 3510bd670b35SErik Nordmark DROPPER(ipss, ipds_sadb_acquire_timeout), 3511bd670b35SErik Nordmark &espstack->esp_dropper); 3512bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards); 3513bd670b35SErik Nordmark } else { 3514bd670b35SErik Nordmark esp_outbound_finish(data_mp, &ixas); 3515bd670b35SErik Nordmark } 3516bd670b35SErik Nordmark ixa_cleanup(&ixas); 35177c478bd9Sstevel@tonic-gate } 35187c478bd9Sstevel@tonic-gate 35197c478bd9Sstevel@tonic-gate return (rc); 35207c478bd9Sstevel@tonic-gate } 35217c478bd9Sstevel@tonic-gate 35227c478bd9Sstevel@tonic-gate /* 3523bd670b35SErik Nordmark * Process one of the queued messages (from ipsacq_mp) once the SA 3524bd670b35SErik Nordmark * has been added. 3525bd670b35SErik Nordmark */ 3526bd670b35SErik Nordmark static void 3527bd670b35SErik Nordmark esp_outbound_finish(mblk_t *data_mp, ip_xmit_attr_t *ixa) 3528bd670b35SErik Nordmark { 3529bd670b35SErik Nordmark netstack_t *ns = ixa->ixa_ipst->ips_netstack; 3530bd670b35SErik Nordmark ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 3531bd670b35SErik Nordmark ipsec_stack_t *ipss = ns->netstack_ipsec; 3532bd670b35SErik Nordmark ill_t *ill = ixa->ixa_nce->nce_ill; 3533bd670b35SErik Nordmark 3534bd670b35SErik Nordmark if (!ipsec_outbound_sa(data_mp, ixa, IPPROTO_ESP)) { 3535bd670b35SErik Nordmark ESP_BUMP_STAT(espstack, out_discards); 3536bd670b35SErik Nordmark ip_drop_packet(data_mp, B_FALSE, ill, 3537bd670b35SErik Nordmark DROPPER(ipss, ipds_sadb_acquire_timeout), 3538bd670b35SErik Nordmark &espstack->esp_dropper); 3539bd670b35SErik Nordmark BUMP_MIB(ill->ill_ip_mib, ipIfStatsOutDiscards); 3540bd670b35SErik Nordmark return; 3541bd670b35SErik Nordmark } 3542bd670b35SErik Nordmark 3543bd670b35SErik Nordmark data_mp = esp_outbound(data_mp, ixa); 3544bd670b35SErik Nordmark if (data_mp == NULL) 3545bd670b35SErik Nordmark return; 3546bd670b35SErik Nordmark 3547bd670b35SErik Nordmark /* do AH processing if needed */ 3548bd670b35SErik Nordmark data_mp = esp_do_outbound_ah(data_mp, ixa); 3549bd670b35SErik Nordmark if (data_mp == NULL) 3550bd670b35SErik Nordmark return; 3551bd670b35SErik Nordmark 3552bd670b35SErik Nordmark (void) ip_output_post_ipsec(data_mp, ixa); 3553bd670b35SErik Nordmark } 3554bd670b35SErik Nordmark 3555bd670b35SErik Nordmark /* 35567c478bd9Sstevel@tonic-gate * Add new ESP security association. This may become a generic AH/ESP 35577c478bd9Sstevel@tonic-gate * routine eventually. 35587c478bd9Sstevel@tonic-gate */ 35597c478bd9Sstevel@tonic-gate static int 3560f4b3ec61Sdh155122 esp_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, netstack_t *ns) 35617c478bd9Sstevel@tonic-gate { 35627c478bd9Sstevel@tonic-gate sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 35637c478bd9Sstevel@tonic-gate sadb_address_t *srcext = 35647c478bd9Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC]; 35657c478bd9Sstevel@tonic-gate sadb_address_t *dstext = 35667c478bd9Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 35678810c16bSdanmcd sadb_address_t *isrcext = 35688810c16bSdanmcd (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_INNER_SRC]; 35698810c16bSdanmcd sadb_address_t *idstext = 35708810c16bSdanmcd (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_INNER_DST]; 35717c478bd9Sstevel@tonic-gate sadb_address_t *nttext_loc = 35727c478bd9Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_LOC]; 35737c478bd9Sstevel@tonic-gate sadb_address_t *nttext_rem = 35747c478bd9Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_X_EXT_ADDRESS_NATT_REM]; 35757c478bd9Sstevel@tonic-gate sadb_key_t *akey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH]; 35767c478bd9Sstevel@tonic-gate sadb_key_t *ekey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT]; 35777c478bd9Sstevel@tonic-gate struct sockaddr_in *src, *dst; 35787c478bd9Sstevel@tonic-gate struct sockaddr_in *natt_loc, *natt_rem; 35797c478bd9Sstevel@tonic-gate struct sockaddr_in6 *natt_loc6, *natt_rem6; 35807c478bd9Sstevel@tonic-gate sadb_lifetime_t *soft = 35817c478bd9Sstevel@tonic-gate (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_SOFT]; 35827c478bd9Sstevel@tonic-gate sadb_lifetime_t *hard = 35837c478bd9Sstevel@tonic-gate (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_HARD]; 35849c2c14abSThejaswini Singarajipura sadb_lifetime_t *idle = 35859c2c14abSThejaswini Singarajipura (sadb_lifetime_t *)ksi->ks_in_extv[SADB_X_EXT_LIFETIME_IDLE]; 3586f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 3587f4b3ec61Sdh155122 ipsec_stack_t *ipss = ns->netstack_ipsec; 35887c478bd9Sstevel@tonic-gate 35895d3b8cb7SBill Sommerfeld 35905d3b8cb7SBill Sommerfeld 35917c478bd9Sstevel@tonic-gate /* I need certain extensions present for an ADD message. */ 35927c478bd9Sstevel@tonic-gate if (srcext == NULL) { 35937c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC; 35947c478bd9Sstevel@tonic-gate return (EINVAL); 35957c478bd9Sstevel@tonic-gate } 35967c478bd9Sstevel@tonic-gate if (dstext == NULL) { 35977c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST; 35987c478bd9Sstevel@tonic-gate return (EINVAL); 35997c478bd9Sstevel@tonic-gate } 36008810c16bSdanmcd if (isrcext == NULL && idstext != NULL) { 36018810c16bSdanmcd *diagnostic = SADB_X_DIAGNOSTIC_MISSING_INNER_SRC; 36028810c16bSdanmcd return (EINVAL); 36038810c16bSdanmcd } 36048810c16bSdanmcd if (isrcext != NULL && idstext == NULL) { 36058810c16bSdanmcd *diagnostic = SADB_X_DIAGNOSTIC_MISSING_INNER_DST; 36068810c16bSdanmcd return (EINVAL); 36078810c16bSdanmcd } 36087c478bd9Sstevel@tonic-gate if (assoc == NULL) { 36097c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA; 36107c478bd9Sstevel@tonic-gate return (EINVAL); 36117c478bd9Sstevel@tonic-gate } 36127c478bd9Sstevel@tonic-gate if (ekey == NULL && assoc->sadb_sa_encrypt != SADB_EALG_NULL) { 36137c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_EKEY; 36147c478bd9Sstevel@tonic-gate return (EINVAL); 36157c478bd9Sstevel@tonic-gate } 36167c478bd9Sstevel@tonic-gate 36177c478bd9Sstevel@tonic-gate src = (struct sockaddr_in *)(srcext + 1); 36187c478bd9Sstevel@tonic-gate dst = (struct sockaddr_in *)(dstext + 1); 36197c478bd9Sstevel@tonic-gate natt_loc = (struct sockaddr_in *)(nttext_loc + 1); 36207c478bd9Sstevel@tonic-gate natt_loc6 = (struct sockaddr_in6 *)(nttext_loc + 1); 36217c478bd9Sstevel@tonic-gate natt_rem = (struct sockaddr_in *)(nttext_rem + 1); 36227c478bd9Sstevel@tonic-gate natt_rem6 = (struct sockaddr_in6 *)(nttext_rem + 1); 36237c478bd9Sstevel@tonic-gate 36247c478bd9Sstevel@tonic-gate /* Sundry ADD-specific reality checks. */ 36257c478bd9Sstevel@tonic-gate /* XXX STATS : Logging/stats here? */ 36269c2c14abSThejaswini Singarajipura 36279c2c14abSThejaswini Singarajipura if ((assoc->sadb_sa_state != SADB_SASTATE_MATURE) && 36289c2c14abSThejaswini Singarajipura (assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE_ELSEWHERE)) { 36297c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE; 36307c478bd9Sstevel@tonic-gate return (EINVAL); 36317c478bd9Sstevel@tonic-gate } 36327c478bd9Sstevel@tonic-gate if (assoc->sadb_sa_encrypt == SADB_EALG_NONE) { 36337c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG; 36347c478bd9Sstevel@tonic-gate return (EINVAL); 36357c478bd9Sstevel@tonic-gate } 36367c478bd9Sstevel@tonic-gate 3637bd670b35SErik Nordmark #ifndef IPSEC_LATENCY_TEST 36387c478bd9Sstevel@tonic-gate if (assoc->sadb_sa_encrypt == SADB_EALG_NULL && 36397c478bd9Sstevel@tonic-gate assoc->sadb_sa_auth == SADB_AALG_NONE) { 36407c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG; 36417c478bd9Sstevel@tonic-gate return (EINVAL); 36427c478bd9Sstevel@tonic-gate } 3643bd670b35SErik Nordmark #endif 36447c478bd9Sstevel@tonic-gate 364572bd9b6bSdanmcd if (assoc->sadb_sa_flags & ~espstack->esp_sadb.s_addflags) { 36467c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_SAFLAGS; 36477c478bd9Sstevel@tonic-gate return (EINVAL); 36487c478bd9Sstevel@tonic-gate } 36497c478bd9Sstevel@tonic-gate 36509c2c14abSThejaswini Singarajipura if ((*diagnostic = sadb_hardsoftchk(hard, soft, idle)) != 0) { 36517c478bd9Sstevel@tonic-gate return (EINVAL); 36527c478bd9Sstevel@tonic-gate } 36538810c16bSdanmcd ASSERT(src->sin_family == dst->sin_family); 36547c478bd9Sstevel@tonic-gate 36557c478bd9Sstevel@tonic-gate if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_LOC) { 36567c478bd9Sstevel@tonic-gate if (nttext_loc == NULL) { 36577c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_NATT_LOC; 36587c478bd9Sstevel@tonic-gate return (EINVAL); 36597c478bd9Sstevel@tonic-gate } 36607c478bd9Sstevel@tonic-gate 36617c478bd9Sstevel@tonic-gate if (natt_loc->sin_family == AF_INET6 && 36627c478bd9Sstevel@tonic-gate !IN6_IS_ADDR_V4MAPPED(&natt_loc6->sin6_addr)) { 36637c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_NATT_LOC; 36647c478bd9Sstevel@tonic-gate return (EINVAL); 36657c478bd9Sstevel@tonic-gate } 36667c478bd9Sstevel@tonic-gate } 36677c478bd9Sstevel@tonic-gate 36687c478bd9Sstevel@tonic-gate if (assoc->sadb_sa_flags & SADB_X_SAFLAGS_NATT_REM) { 36697c478bd9Sstevel@tonic-gate if (nttext_rem == NULL) { 36707c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_NATT_REM; 36717c478bd9Sstevel@tonic-gate return (EINVAL); 36727c478bd9Sstevel@tonic-gate } 36737c478bd9Sstevel@tonic-gate if (natt_rem->sin_family == AF_INET6 && 36747c478bd9Sstevel@tonic-gate !IN6_IS_ADDR_V4MAPPED(&natt_rem6->sin6_addr)) { 36757c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MALFORMED_NATT_REM; 36767c478bd9Sstevel@tonic-gate return (EINVAL); 36777c478bd9Sstevel@tonic-gate } 36787c478bd9Sstevel@tonic-gate } 36797c478bd9Sstevel@tonic-gate 36807c478bd9Sstevel@tonic-gate 36817c478bd9Sstevel@tonic-gate /* Stuff I don't support, for now. XXX Diagnostic? */ 36825d3b8cb7SBill Sommerfeld if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL) 36837c478bd9Sstevel@tonic-gate return (EOPNOTSUPP); 36847c478bd9Sstevel@tonic-gate 36855d3b8cb7SBill Sommerfeld if ((*diagnostic = sadb_labelchk(ksi)) != 0) 36865d3b8cb7SBill Sommerfeld return (EINVAL); 36875d3b8cb7SBill Sommerfeld 36887c478bd9Sstevel@tonic-gate /* 36895d3b8cb7SBill Sommerfeld * XXX Policy : I'm not checking identities at this time, 36905d3b8cb7SBill Sommerfeld * but if I did, I'd do them here, before I sent 36917c478bd9Sstevel@tonic-gate * the weak key check up to the algorithm. 36927c478bd9Sstevel@tonic-gate */ 36937c478bd9Sstevel@tonic-gate 3694f4b3ec61Sdh155122 mutex_enter(&ipss->ipsec_alg_lock); 36957c478bd9Sstevel@tonic-gate 36967c478bd9Sstevel@tonic-gate /* 36977c478bd9Sstevel@tonic-gate * First locate the authentication algorithm. 36987c478bd9Sstevel@tonic-gate */ 3699bd670b35SErik Nordmark #ifdef IPSEC_LATENCY_TEST 3700bd670b35SErik Nordmark if (akey != NULL && assoc->sadb_sa_auth != SADB_AALG_NONE) { 3701bd670b35SErik Nordmark #else 37027c478bd9Sstevel@tonic-gate if (akey != NULL) { 3703bd670b35SErik Nordmark #endif 37047c478bd9Sstevel@tonic-gate ipsec_alginfo_t *aalg; 37057c478bd9Sstevel@tonic-gate 3706f4b3ec61Sdh155122 aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH] 3707f4b3ec61Sdh155122 [assoc->sadb_sa_auth]; 37087c478bd9Sstevel@tonic-gate if (aalg == NULL || !ALG_VALID(aalg)) { 3709f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 3710f4b3ec61Sdh155122 esp1dbg(espstack, ("Couldn't find auth alg #%d.\n", 37117c478bd9Sstevel@tonic-gate assoc->sadb_sa_auth)); 37127c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG; 37137c478bd9Sstevel@tonic-gate return (EINVAL); 37147c478bd9Sstevel@tonic-gate } 37157c478bd9Sstevel@tonic-gate 371646c444baSmarkfen /* 371746c444baSmarkfen * Sanity check key sizes. 371846c444baSmarkfen * Note: It's not possible to use SADB_AALG_NONE because 371946c444baSmarkfen * this auth_alg is not defined with ALG_FLAG_VALID. If this 372046c444baSmarkfen * ever changes, the same check for SADB_AALG_NONE and 372146c444baSmarkfen * a auth_key != NULL should be made here ( see below). 372246c444baSmarkfen */ 37237c478bd9Sstevel@tonic-gate if (!ipsec_valid_key_size(akey->sadb_key_bits, aalg)) { 3724f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 37257c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_AKEYBITS; 37267c478bd9Sstevel@tonic-gate return (EINVAL); 37277c478bd9Sstevel@tonic-gate } 372846c444baSmarkfen ASSERT(aalg->alg_mech_type != CRYPTO_MECHANISM_INVALID); 37297c478bd9Sstevel@tonic-gate 37307c478bd9Sstevel@tonic-gate /* check key and fix parity if needed */ 37317c478bd9Sstevel@tonic-gate if (ipsec_check_key(aalg->alg_mech_type, akey, B_TRUE, 37327c478bd9Sstevel@tonic-gate diagnostic) != 0) { 3733f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 37347c478bd9Sstevel@tonic-gate return (EINVAL); 37357c478bd9Sstevel@tonic-gate } 37367c478bd9Sstevel@tonic-gate } 37377c478bd9Sstevel@tonic-gate 37387c478bd9Sstevel@tonic-gate /* 37397c478bd9Sstevel@tonic-gate * Then locate the encryption algorithm. 37407c478bd9Sstevel@tonic-gate */ 37417c478bd9Sstevel@tonic-gate if (ekey != NULL) { 3742628b0c67SMark Fenwick uint_t keybits; 37437c478bd9Sstevel@tonic-gate ipsec_alginfo_t *ealg; 37447c478bd9Sstevel@tonic-gate 3745f4b3ec61Sdh155122 ealg = ipss->ipsec_alglists[IPSEC_ALG_ENCR] 3746f4b3ec61Sdh155122 [assoc->sadb_sa_encrypt]; 37477c478bd9Sstevel@tonic-gate if (ealg == NULL || !ALG_VALID(ealg)) { 3748f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 3749f4b3ec61Sdh155122 esp1dbg(espstack, ("Couldn't find encr alg #%d.\n", 37507c478bd9Sstevel@tonic-gate assoc->sadb_sa_encrypt)); 37517c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_EALG; 37527c478bd9Sstevel@tonic-gate return (EINVAL); 37537c478bd9Sstevel@tonic-gate } 37547c478bd9Sstevel@tonic-gate 375546c444baSmarkfen /* 375646c444baSmarkfen * Sanity check key sizes. If the encryption algorithm is 375746c444baSmarkfen * SADB_EALG_NULL but the encryption key is NOT 375846c444baSmarkfen * NULL then complain. 3759628b0c67SMark Fenwick * 3760628b0c67SMark Fenwick * The keying material includes salt bits if required by 3761628b0c67SMark Fenwick * algorithm and optionally the Initial IV, check the 3762628b0c67SMark Fenwick * length of whats left. 376346c444baSmarkfen */ 3764628b0c67SMark Fenwick keybits = ekey->sadb_key_bits; 3765628b0c67SMark Fenwick keybits -= ekey->sadb_key_reserved; 3766628b0c67SMark Fenwick keybits -= SADB_8TO1(ealg->alg_saltlen); 376746c444baSmarkfen if ((assoc->sadb_sa_encrypt == SADB_EALG_NULL) || 3768628b0c67SMark Fenwick (!ipsec_valid_key_size(keybits, ealg))) { 3769f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 37707c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_BAD_EKEYBITS; 37717c478bd9Sstevel@tonic-gate return (EINVAL); 37727c478bd9Sstevel@tonic-gate } 377346c444baSmarkfen ASSERT(ealg->alg_mech_type != CRYPTO_MECHANISM_INVALID); 37747c478bd9Sstevel@tonic-gate 37757c478bd9Sstevel@tonic-gate /* check key */ 37767c478bd9Sstevel@tonic-gate if (ipsec_check_key(ealg->alg_mech_type, ekey, B_FALSE, 37777c478bd9Sstevel@tonic-gate diagnostic) != 0) { 3778f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 37797c478bd9Sstevel@tonic-gate return (EINVAL); 37807c478bd9Sstevel@tonic-gate } 37817c478bd9Sstevel@tonic-gate } 3782f4b3ec61Sdh155122 mutex_exit(&ipss->ipsec_alg_lock); 37837c478bd9Sstevel@tonic-gate 37848810c16bSdanmcd return (esp_add_sa_finish(mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi, 3785f4b3ec61Sdh155122 diagnostic, espstack)); 37867c478bd9Sstevel@tonic-gate } 37877c478bd9Sstevel@tonic-gate 37887c478bd9Sstevel@tonic-gate /* 37897c478bd9Sstevel@tonic-gate * Update a security association. Updates come in two varieties. The first 37907c478bd9Sstevel@tonic-gate * is an update of lifetimes on a non-larval SA. The second is an update of 37917c478bd9Sstevel@tonic-gate * a larval SA, which ends up looking a lot more like an add. 37927c478bd9Sstevel@tonic-gate */ 37937c478bd9Sstevel@tonic-gate static int 3794f4b3ec61Sdh155122 esp_update_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, 379538d95a78Smarkfen ipsecesp_stack_t *espstack, uint8_t sadb_msg_type) 37967c478bd9Sstevel@tonic-gate { 37979c2c14abSThejaswini Singarajipura sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 37989c2c14abSThejaswini Singarajipura mblk_t *buf_pkt; 37999c2c14abSThejaswini Singarajipura int rcode; 38009c2c14abSThejaswini Singarajipura 38017c478bd9Sstevel@tonic-gate sadb_address_t *dstext = 38027c478bd9Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 38037c478bd9Sstevel@tonic-gate 38047c478bd9Sstevel@tonic-gate if (dstext == NULL) { 38057c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST; 38067c478bd9Sstevel@tonic-gate return (EINVAL); 38077c478bd9Sstevel@tonic-gate } 38087c478bd9Sstevel@tonic-gate 38099c2c14abSThejaswini Singarajipura rcode = sadb_update_sa(mp, ksi, &buf_pkt, &espstack->esp_sadb, 38109c2c14abSThejaswini Singarajipura diagnostic, espstack->esp_pfkey_q, esp_add_sa, 38119c2c14abSThejaswini Singarajipura espstack->ipsecesp_netstack, sadb_msg_type); 38129c2c14abSThejaswini Singarajipura 38139c2c14abSThejaswini Singarajipura if ((assoc->sadb_sa_state != SADB_X_SASTATE_ACTIVE) || 38149c2c14abSThejaswini Singarajipura (rcode != 0)) { 38159c2c14abSThejaswini Singarajipura return (rcode); 38169c2c14abSThejaswini Singarajipura } 38179c2c14abSThejaswini Singarajipura 381873184bc7SDan McDonald HANDLE_BUF_PKT(esp_taskq, espstack->ipsecesp_netstack->netstack_ipsec, 38199c2c14abSThejaswini Singarajipura espstack->esp_dropper, buf_pkt); 38209c2c14abSThejaswini Singarajipura 38219c2c14abSThejaswini Singarajipura return (rcode); 38227c478bd9Sstevel@tonic-gate } 38237c478bd9Sstevel@tonic-gate 38245d3b8cb7SBill Sommerfeld /* XXX refactor me */ 38257c478bd9Sstevel@tonic-gate /* 38267c478bd9Sstevel@tonic-gate * Delete a security association. This is REALLY likely to be code common to 38277c478bd9Sstevel@tonic-gate * both AH and ESP. Find the association, then unlink it. 38287c478bd9Sstevel@tonic-gate */ 38297c478bd9Sstevel@tonic-gate static int 3830f4b3ec61Sdh155122 esp_del_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic, 383138d95a78Smarkfen ipsecesp_stack_t *espstack, uint8_t sadb_msg_type) 38327c478bd9Sstevel@tonic-gate { 38337c478bd9Sstevel@tonic-gate sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 38347c478bd9Sstevel@tonic-gate sadb_address_t *dstext = 38357c478bd9Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 38367c478bd9Sstevel@tonic-gate sadb_address_t *srcext = 38377c478bd9Sstevel@tonic-gate (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC]; 38387c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 38397c478bd9Sstevel@tonic-gate 38407c478bd9Sstevel@tonic-gate if (assoc == NULL) { 38417c478bd9Sstevel@tonic-gate if (dstext != NULL) { 38427c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)(dstext + 1); 38437c478bd9Sstevel@tonic-gate } else if (srcext != NULL) { 38447c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)(srcext + 1); 38457c478bd9Sstevel@tonic-gate } else { 38467c478bd9Sstevel@tonic-gate *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA; 38477c478bd9Sstevel@tonic-gate return (EINVAL); 38487c478bd9Sstevel@tonic-gate } 38498810c16bSdanmcd return (sadb_purge_sa(mp, ksi, 3850f4b3ec61Sdh155122 (sin->sin_family == AF_INET6) ? &espstack->esp_sadb.s_v6 : 38515d3b8cb7SBill Sommerfeld &espstack->esp_sadb.s_v4, diagnostic, 3852bd670b35SErik Nordmark espstack->esp_pfkey_q)); 38537c478bd9Sstevel@tonic-gate } 38547c478bd9Sstevel@tonic-gate 385538d95a78Smarkfen return (sadb_delget_sa(mp, ksi, &espstack->esp_sadb, diagnostic, 385638d95a78Smarkfen espstack->esp_pfkey_q, sadb_msg_type)); 38577c478bd9Sstevel@tonic-gate } 38587c478bd9Sstevel@tonic-gate 38595d3b8cb7SBill Sommerfeld /* XXX refactor me */ 38607c478bd9Sstevel@tonic-gate /* 38617c478bd9Sstevel@tonic-gate * Convert the entire contents of all of ESP's SA tables into PF_KEY SADB_DUMP 38627c478bd9Sstevel@tonic-gate * messages. 38637c478bd9Sstevel@tonic-gate */ 38647c478bd9Sstevel@tonic-gate static void 3865f4b3ec61Sdh155122 esp_dump(mblk_t *mp, keysock_in_t *ksi, ipsecesp_stack_t *espstack) 38667c478bd9Sstevel@tonic-gate { 38677c478bd9Sstevel@tonic-gate int error; 38687c478bd9Sstevel@tonic-gate sadb_msg_t *samsg; 38697c478bd9Sstevel@tonic-gate 38707c478bd9Sstevel@tonic-gate /* 38717c478bd9Sstevel@tonic-gate * Dump each fanout, bailing if error is non-zero. 38727c478bd9Sstevel@tonic-gate */ 38737c478bd9Sstevel@tonic-gate 38749c2c14abSThejaswini Singarajipura error = sadb_dump(espstack->esp_pfkey_q, mp, ksi, 3875f4b3ec61Sdh155122 &espstack->esp_sadb.s_v4); 38767c478bd9Sstevel@tonic-gate if (error != 0) 38777c478bd9Sstevel@tonic-gate goto bail; 38787c478bd9Sstevel@tonic-gate 38799c2c14abSThejaswini Singarajipura error = sadb_dump(espstack->esp_pfkey_q, mp, ksi, 3880f4b3ec61Sdh155122 &espstack->esp_sadb.s_v6); 38817c478bd9Sstevel@tonic-gate bail: 38827c478bd9Sstevel@tonic-gate ASSERT(mp->b_cont != NULL); 38837c478bd9Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_cont->b_rptr; 38847c478bd9Sstevel@tonic-gate samsg->sadb_msg_errno = (uint8_t)error; 3885f4b3ec61Sdh155122 sadb_pfkey_echo(espstack->esp_pfkey_q, mp, 3886f4b3ec61Sdh155122 (sadb_msg_t *)mp->b_cont->b_rptr, ksi, NULL); 38877c478bd9Sstevel@tonic-gate } 38887c478bd9Sstevel@tonic-gate 38897c478bd9Sstevel@tonic-gate /* 38908810c16bSdanmcd * First-cut reality check for an inbound PF_KEY message. 38918810c16bSdanmcd */ 38928810c16bSdanmcd static boolean_t 3893f4b3ec61Sdh155122 esp_pfkey_reality_failures(mblk_t *mp, keysock_in_t *ksi, 3894f4b3ec61Sdh155122 ipsecesp_stack_t *espstack) 38958810c16bSdanmcd { 38968810c16bSdanmcd int diagnostic; 38978810c16bSdanmcd 38988810c16bSdanmcd if (ksi->ks_in_extv[SADB_EXT_PROPOSAL] != NULL) { 38998810c16bSdanmcd diagnostic = SADB_X_DIAGNOSTIC_PROP_PRESENT; 39008810c16bSdanmcd goto badmsg; 39018810c16bSdanmcd } 39028810c16bSdanmcd if (ksi->ks_in_extv[SADB_EXT_SUPPORTED_AUTH] != NULL || 39038810c16bSdanmcd ksi->ks_in_extv[SADB_EXT_SUPPORTED_ENCRYPT] != NULL) { 39048810c16bSdanmcd diagnostic = SADB_X_DIAGNOSTIC_SUPP_PRESENT; 39058810c16bSdanmcd goto badmsg; 39068810c16bSdanmcd } 39078810c16bSdanmcd return (B_FALSE); /* False ==> no failures */ 39088810c16bSdanmcd 39098810c16bSdanmcd badmsg: 3910f4b3ec61Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, EINVAL, diagnostic, 39118810c16bSdanmcd ksi->ks_in_serial); 39128810c16bSdanmcd return (B_TRUE); /* True ==> failures */ 39138810c16bSdanmcd } 39148810c16bSdanmcd 39158810c16bSdanmcd /* 39167c478bd9Sstevel@tonic-gate * ESP parsing of PF_KEY messages. Keysock did most of the really silly 39177c478bd9Sstevel@tonic-gate * error cases. What I receive is a fully-formed, syntactically legal 39187c478bd9Sstevel@tonic-gate * PF_KEY message. I then need to check semantics... 39197c478bd9Sstevel@tonic-gate * 39207c478bd9Sstevel@tonic-gate * This code may become common to AH and ESP. Stay tuned. 39217c478bd9Sstevel@tonic-gate * 39227c478bd9Sstevel@tonic-gate * I also make the assumption that db_ref's are cool. If this assumption 39237c478bd9Sstevel@tonic-gate * is wrong, this means that someone other than keysock or me has been 39247c478bd9Sstevel@tonic-gate * mucking with PF_KEY messages. 39257c478bd9Sstevel@tonic-gate */ 39267c478bd9Sstevel@tonic-gate static void 3927f4b3ec61Sdh155122 esp_parse_pfkey(mblk_t *mp, ipsecesp_stack_t *espstack) 39287c478bd9Sstevel@tonic-gate { 39297c478bd9Sstevel@tonic-gate mblk_t *msg = mp->b_cont; 39307c478bd9Sstevel@tonic-gate sadb_msg_t *samsg; 39317c478bd9Sstevel@tonic-gate keysock_in_t *ksi; 39327c478bd9Sstevel@tonic-gate int error; 39337c478bd9Sstevel@tonic-gate int diagnostic = SADB_X_DIAGNOSTIC_NONE; 39347c478bd9Sstevel@tonic-gate 39357c478bd9Sstevel@tonic-gate ASSERT(msg != NULL); 3936f4b3ec61Sdh155122 39377c478bd9Sstevel@tonic-gate samsg = (sadb_msg_t *)msg->b_rptr; 39387c478bd9Sstevel@tonic-gate ksi = (keysock_in_t *)mp->b_rptr; 39397c478bd9Sstevel@tonic-gate 39407c478bd9Sstevel@tonic-gate /* 39417c478bd9Sstevel@tonic-gate * If applicable, convert unspecified AF_INET6 to unspecified 39428810c16bSdanmcd * AF_INET. And do other address reality checks. 39437c478bd9Sstevel@tonic-gate */ 3944f4b3ec61Sdh155122 if (!sadb_addrfix(ksi, espstack->esp_pfkey_q, mp, 3945f4b3ec61Sdh155122 espstack->ipsecesp_netstack) || 3946f4b3ec61Sdh155122 esp_pfkey_reality_failures(mp, ksi, espstack)) { 39478810c16bSdanmcd return; 39488810c16bSdanmcd } 39497c478bd9Sstevel@tonic-gate 39507c478bd9Sstevel@tonic-gate switch (samsg->sadb_msg_type) { 39517c478bd9Sstevel@tonic-gate case SADB_ADD: 3952f4b3ec61Sdh155122 error = esp_add_sa(mp, ksi, &diagnostic, 3953f4b3ec61Sdh155122 espstack->ipsecesp_netstack); 39547c478bd9Sstevel@tonic-gate if (error != 0) { 3955f4b3ec61Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, error, 3956f4b3ec61Sdh155122 diagnostic, ksi->ks_in_serial); 39577c478bd9Sstevel@tonic-gate } 39587c478bd9Sstevel@tonic-gate /* else esp_add_sa() took care of things. */ 39597c478bd9Sstevel@tonic-gate break; 39607c478bd9Sstevel@tonic-gate case SADB_DELETE: 396138d95a78Smarkfen case SADB_X_DELPAIR: 39629c2c14abSThejaswini Singarajipura case SADB_X_DELPAIR_STATE: 396338d95a78Smarkfen error = esp_del_sa(mp, ksi, &diagnostic, espstack, 396438d95a78Smarkfen samsg->sadb_msg_type); 39657c478bd9Sstevel@tonic-gate if (error != 0) { 3966f4b3ec61Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, error, 3967f4b3ec61Sdh155122 diagnostic, ksi->ks_in_serial); 39687c478bd9Sstevel@tonic-gate } 39697c478bd9Sstevel@tonic-gate /* Else esp_del_sa() took care of things. */ 39707c478bd9Sstevel@tonic-gate break; 39717c478bd9Sstevel@tonic-gate case SADB_GET: 397238d95a78Smarkfen error = sadb_delget_sa(mp, ksi, &espstack->esp_sadb, 397338d95a78Smarkfen &diagnostic, espstack->esp_pfkey_q, samsg->sadb_msg_type); 39747c478bd9Sstevel@tonic-gate if (error != 0) { 3975f4b3ec61Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, error, 3976f4b3ec61Sdh155122 diagnostic, ksi->ks_in_serial); 39777c478bd9Sstevel@tonic-gate } 39787c478bd9Sstevel@tonic-gate /* Else sadb_get_sa() took care of things. */ 39797c478bd9Sstevel@tonic-gate break; 39807c478bd9Sstevel@tonic-gate case SADB_FLUSH: 3981f4b3ec61Sdh155122 sadbp_flush(&espstack->esp_sadb, espstack->ipsecesp_netstack); 3982f4b3ec61Sdh155122 sadb_pfkey_echo(espstack->esp_pfkey_q, mp, samsg, ksi, NULL); 39837c478bd9Sstevel@tonic-gate break; 39847c478bd9Sstevel@tonic-gate case SADB_REGISTER: 39857c478bd9Sstevel@tonic-gate /* 39867c478bd9Sstevel@tonic-gate * Hmmm, let's do it! Check for extensions (there should 39877c478bd9Sstevel@tonic-gate * be none), extract the fields, call esp_register_out(), 39887c478bd9Sstevel@tonic-gate * then either free or report an error. 39897c478bd9Sstevel@tonic-gate * 39907c478bd9Sstevel@tonic-gate * Keysock takes care of the PF_KEY bookkeeping for this. 39917c478bd9Sstevel@tonic-gate */ 39927c478bd9Sstevel@tonic-gate if (esp_register_out(samsg->sadb_msg_seq, samsg->sadb_msg_pid, 3993bd670b35SErik Nordmark ksi->ks_in_serial, espstack, msg_getcred(mp, NULL))) { 39947c478bd9Sstevel@tonic-gate freemsg(mp); 39957c478bd9Sstevel@tonic-gate } else { 39967c478bd9Sstevel@tonic-gate /* 39977c478bd9Sstevel@tonic-gate * Only way this path hits is if there is a memory 39987c478bd9Sstevel@tonic-gate * failure. It will not return B_FALSE because of 39997c478bd9Sstevel@tonic-gate * lack of esp_pfkey_q if I am in wput(). 40007c478bd9Sstevel@tonic-gate */ 4001f4b3ec61Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, ENOMEM, 4002f4b3ec61Sdh155122 diagnostic, ksi->ks_in_serial); 40037c478bd9Sstevel@tonic-gate } 40047c478bd9Sstevel@tonic-gate break; 40057c478bd9Sstevel@tonic-gate case SADB_UPDATE: 400638d95a78Smarkfen case SADB_X_UPDATEPAIR: 40077c478bd9Sstevel@tonic-gate /* 40087c478bd9Sstevel@tonic-gate * Find a larval, if not there, find a full one and get 40097c478bd9Sstevel@tonic-gate * strict. 40107c478bd9Sstevel@tonic-gate */ 401138d95a78Smarkfen error = esp_update_sa(mp, ksi, &diagnostic, espstack, 401238d95a78Smarkfen samsg->sadb_msg_type); 40137c478bd9Sstevel@tonic-gate if (error != 0) { 4014f4b3ec61Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, error, 4015f4b3ec61Sdh155122 diagnostic, ksi->ks_in_serial); 40167c478bd9Sstevel@tonic-gate } 40177c478bd9Sstevel@tonic-gate /* else esp_update_sa() took care of things. */ 40187c478bd9Sstevel@tonic-gate break; 40197c478bd9Sstevel@tonic-gate case SADB_GETSPI: 40207c478bd9Sstevel@tonic-gate /* 40217c478bd9Sstevel@tonic-gate * Reserve a new larval entry. 40227c478bd9Sstevel@tonic-gate */ 4023f4b3ec61Sdh155122 esp_getspi(mp, ksi, espstack); 40247c478bd9Sstevel@tonic-gate break; 40257c478bd9Sstevel@tonic-gate case SADB_ACQUIRE: 40267c478bd9Sstevel@tonic-gate /* 40277c478bd9Sstevel@tonic-gate * Find larval and/or ACQUIRE record and kill it (them), I'm 40287c478bd9Sstevel@tonic-gate * most likely an error. Inbound ACQUIRE messages should only 40297c478bd9Sstevel@tonic-gate * have the base header. 40307c478bd9Sstevel@tonic-gate */ 4031f4b3ec61Sdh155122 sadb_in_acquire(samsg, &espstack->esp_sadb, 4032f4b3ec61Sdh155122 espstack->esp_pfkey_q, espstack->ipsecesp_netstack); 40337c478bd9Sstevel@tonic-gate freemsg(mp); 40347c478bd9Sstevel@tonic-gate break; 40357c478bd9Sstevel@tonic-gate case SADB_DUMP: 40367c478bd9Sstevel@tonic-gate /* 40377c478bd9Sstevel@tonic-gate * Dump all entries. 40387c478bd9Sstevel@tonic-gate */ 4039f4b3ec61Sdh155122 esp_dump(mp, ksi, espstack); 40407c478bd9Sstevel@tonic-gate /* esp_dump will take care of the return message, etc. */ 40417c478bd9Sstevel@tonic-gate break; 40427c478bd9Sstevel@tonic-gate case SADB_EXPIRE: 40437c478bd9Sstevel@tonic-gate /* Should never reach me. */ 4044f4b3ec61Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, EOPNOTSUPP, 4045f4b3ec61Sdh155122 diagnostic, ksi->ks_in_serial); 40467c478bd9Sstevel@tonic-gate break; 40477c478bd9Sstevel@tonic-gate default: 4048f4b3ec61Sdh155122 sadb_pfkey_error(espstack->esp_pfkey_q, mp, EINVAL, 40497c478bd9Sstevel@tonic-gate SADB_X_DIAGNOSTIC_UNKNOWN_MSG, ksi->ks_in_serial); 40507c478bd9Sstevel@tonic-gate break; 40517c478bd9Sstevel@tonic-gate } 40527c478bd9Sstevel@tonic-gate } 40537c478bd9Sstevel@tonic-gate 40547c478bd9Sstevel@tonic-gate /* 40557c478bd9Sstevel@tonic-gate * Handle case where PF_KEY says it can't find a keysock for one of my 40567c478bd9Sstevel@tonic-gate * ACQUIRE messages. 40577c478bd9Sstevel@tonic-gate */ 40587c478bd9Sstevel@tonic-gate static void 4059f4b3ec61Sdh155122 esp_keysock_no_socket(mblk_t *mp, ipsecesp_stack_t *espstack) 40607c478bd9Sstevel@tonic-gate { 40617c478bd9Sstevel@tonic-gate sadb_msg_t *samsg; 40627c478bd9Sstevel@tonic-gate keysock_out_err_t *kse = (keysock_out_err_t *)mp->b_rptr; 40637c478bd9Sstevel@tonic-gate 40647c478bd9Sstevel@tonic-gate if (mp->b_cont == NULL) { 40657c478bd9Sstevel@tonic-gate freemsg(mp); 40667c478bd9Sstevel@tonic-gate return; 40677c478bd9Sstevel@tonic-gate } 40687c478bd9Sstevel@tonic-gate samsg = (sadb_msg_t *)mp->b_cont->b_rptr; 40697c478bd9Sstevel@tonic-gate 40707c478bd9Sstevel@tonic-gate /* 40717c478bd9Sstevel@tonic-gate * If keysock can't find any registered, delete the acquire record 40727c478bd9Sstevel@tonic-gate * immediately, and handle errors. 40737c478bd9Sstevel@tonic-gate */ 40747c478bd9Sstevel@tonic-gate if (samsg->sadb_msg_type == SADB_ACQUIRE) { 40757c478bd9Sstevel@tonic-gate samsg->sadb_msg_errno = kse->ks_err_errno; 40767c478bd9Sstevel@tonic-gate samsg->sadb_msg_len = SADB_8TO64(sizeof (*samsg)); 40777c478bd9Sstevel@tonic-gate /* 4078bd670b35SErik Nordmark * Use the write-side of the esp_pfkey_q 40797c478bd9Sstevel@tonic-gate */ 4080f4b3ec61Sdh155122 sadb_in_acquire(samsg, &espstack->esp_sadb, 4081f4b3ec61Sdh155122 WR(espstack->esp_pfkey_q), espstack->ipsecesp_netstack); 40827c478bd9Sstevel@tonic-gate } 40837c478bd9Sstevel@tonic-gate 40847c478bd9Sstevel@tonic-gate freemsg(mp); 40857c478bd9Sstevel@tonic-gate } 40867c478bd9Sstevel@tonic-gate 40877c478bd9Sstevel@tonic-gate /* 40887c478bd9Sstevel@tonic-gate * ESP module write put routine. 40897c478bd9Sstevel@tonic-gate */ 40907c478bd9Sstevel@tonic-gate static void 40917c478bd9Sstevel@tonic-gate ipsecesp_wput(queue_t *q, mblk_t *mp) 40927c478bd9Sstevel@tonic-gate { 40937c478bd9Sstevel@tonic-gate ipsec_info_t *ii; 40947c478bd9Sstevel@tonic-gate struct iocblk *iocp; 4095f4b3ec61Sdh155122 ipsecesp_stack_t *espstack = (ipsecesp_stack_t *)q->q_ptr; 40967c478bd9Sstevel@tonic-gate 4097f4b3ec61Sdh155122 esp3dbg(espstack, ("In esp_wput().\n")); 40987c478bd9Sstevel@tonic-gate 40997c478bd9Sstevel@tonic-gate /* NOTE: Each case must take care of freeing or passing mp. */ 41007c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 41017c478bd9Sstevel@tonic-gate case M_CTL: 41027c478bd9Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (ipsec_info_t)) { 41037c478bd9Sstevel@tonic-gate /* Not big enough message. */ 41047c478bd9Sstevel@tonic-gate freemsg(mp); 41057c478bd9Sstevel@tonic-gate break; 41067c478bd9Sstevel@tonic-gate } 41077c478bd9Sstevel@tonic-gate ii = (ipsec_info_t *)mp->b_rptr; 41087c478bd9Sstevel@tonic-gate 41097c478bd9Sstevel@tonic-gate switch (ii->ipsec_info_type) { 41107c478bd9Sstevel@tonic-gate case KEYSOCK_OUT_ERR: 4111f4b3ec61Sdh155122 esp1dbg(espstack, ("Got KEYSOCK_OUT_ERR message.\n")); 4112f4b3ec61Sdh155122 esp_keysock_no_socket(mp, espstack); 41137c478bd9Sstevel@tonic-gate break; 41147c478bd9Sstevel@tonic-gate case KEYSOCK_IN: 4115f4b3ec61Sdh155122 ESP_BUMP_STAT(espstack, keysock_in); 4116f4b3ec61Sdh155122 esp3dbg(espstack, ("Got KEYSOCK_IN message.\n")); 41177c478bd9Sstevel@tonic-gate 41188810c16bSdanmcd /* Parse the message. */ 4119f4b3ec61Sdh155122 esp_parse_pfkey(mp, espstack); 41207c478bd9Sstevel@tonic-gate break; 41217c478bd9Sstevel@tonic-gate case KEYSOCK_HELLO: 4122f4b3ec61Sdh155122 sadb_keysock_hello(&espstack->esp_pfkey_q, q, mp, 4123f4b3ec61Sdh155122 esp_ager, (void *)espstack, &espstack->esp_event, 4124f4b3ec61Sdh155122 SADB_SATYPE_ESP); 41257c478bd9Sstevel@tonic-gate break; 41267c478bd9Sstevel@tonic-gate default: 4127f4b3ec61Sdh155122 esp2dbg(espstack, ("Got M_CTL from above of 0x%x.\n", 41287c478bd9Sstevel@tonic-gate ii->ipsec_info_type)); 41297c478bd9Sstevel@tonic-gate freemsg(mp); 41307c478bd9Sstevel@tonic-gate break; 41317c478bd9Sstevel@tonic-gate } 41327c478bd9Sstevel@tonic-gate break; 41337c478bd9Sstevel@tonic-gate case M_IOCTL: 41347c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 41357c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 41367c478bd9Sstevel@tonic-gate case ND_SET: 41377c478bd9Sstevel@tonic-gate case ND_GET: 4138f4b3ec61Sdh155122 if (nd_getset(q, espstack->ipsecesp_g_nd, mp)) { 41397c478bd9Sstevel@tonic-gate qreply(q, mp); 41407c478bd9Sstevel@tonic-gate return; 41417c478bd9Sstevel@tonic-gate } else { 41427c478bd9Sstevel@tonic-gate iocp->ioc_error = ENOENT; 41437c478bd9Sstevel@tonic-gate } 41447c478bd9Sstevel@tonic-gate /* FALLTHRU */ 41457c478bd9Sstevel@tonic-gate default: 41467c478bd9Sstevel@tonic-gate /* We really don't support any other ioctls, do we? */ 41477c478bd9Sstevel@tonic-gate 41487c478bd9Sstevel@tonic-gate /* Return EINVAL */ 41497c478bd9Sstevel@tonic-gate if (iocp->ioc_error != ENOENT) 41507c478bd9Sstevel@tonic-gate iocp->ioc_error = EINVAL; 41517c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; 41527c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 41537c478bd9Sstevel@tonic-gate qreply(q, mp); 41547c478bd9Sstevel@tonic-gate return; 41557c478bd9Sstevel@tonic-gate } 41567c478bd9Sstevel@tonic-gate default: 4157f4b3ec61Sdh155122 esp3dbg(espstack, 4158f4b3ec61Sdh155122 ("Got default message, type %d, passing to IP.\n", 41597c478bd9Sstevel@tonic-gate mp->b_datap->db_type)); 41607c478bd9Sstevel@tonic-gate putnext(q, mp); 41617c478bd9Sstevel@tonic-gate } 41627c478bd9Sstevel@tonic-gate } 41637c478bd9Sstevel@tonic-gate 41647c478bd9Sstevel@tonic-gate /* 41657c478bd9Sstevel@tonic-gate * Wrapper to allow IP to trigger an ESP association failure message 41667c478bd9Sstevel@tonic-gate * during inbound SA selection. 41677c478bd9Sstevel@tonic-gate */ 41687c478bd9Sstevel@tonic-gate void 41697c478bd9Sstevel@tonic-gate ipsecesp_in_assocfailure(mblk_t *mp, char level, ushort_t sl, char *fmt, 4170bd670b35SErik Nordmark uint32_t spi, void *addr, int af, ip_recv_attr_t *ira) 41717c478bd9Sstevel@tonic-gate { 4172bd670b35SErik Nordmark netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack; 4173bd670b35SErik Nordmark ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 4174bd670b35SErik Nordmark ipsec_stack_t *ipss = ns->netstack_ipsec; 4175f4b3ec61Sdh155122 4176f4b3ec61Sdh155122 if (espstack->ipsecesp_log_unknown_spi) { 41777c478bd9Sstevel@tonic-gate ipsec_assocfailure(info.mi_idnum, 0, level, sl, fmt, spi, 4178f4b3ec61Sdh155122 addr, af, espstack->ipsecesp_netstack); 41797c478bd9Sstevel@tonic-gate } 41807c478bd9Sstevel@tonic-gate 4181bd670b35SErik Nordmark ip_drop_packet(mp, B_TRUE, ira->ira_ill, 4182f4b3ec61Sdh155122 DROPPER(ipss, ipds_esp_no_sa), 4183f4b3ec61Sdh155122 &espstack->esp_dropper); 41847c478bd9Sstevel@tonic-gate } 41857c478bd9Sstevel@tonic-gate 41867c478bd9Sstevel@tonic-gate /* 41877c478bd9Sstevel@tonic-gate * Initialize the ESP input and output processing functions. 41887c478bd9Sstevel@tonic-gate */ 41897c478bd9Sstevel@tonic-gate void 41907c478bd9Sstevel@tonic-gate ipsecesp_init_funcs(ipsa_t *sa) 41917c478bd9Sstevel@tonic-gate { 41927c478bd9Sstevel@tonic-gate if (sa->ipsa_output_func == NULL) 41937c478bd9Sstevel@tonic-gate sa->ipsa_output_func = esp_outbound; 41947c478bd9Sstevel@tonic-gate if (sa->ipsa_input_func == NULL) 41957c478bd9Sstevel@tonic-gate sa->ipsa_input_func = esp_inbound; 41967c478bd9Sstevel@tonic-gate } 4197