1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1659 markfen * Common Development and Distribution License (the "License"). 6 1659 markfen * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 8705 danmcd * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel #include <sys/types.h> 27 0 stevel #include <sys/stream.h> 28 10934 sommerfeld #include <sys/strsubr.h> 29 0 stevel #include <sys/sunddi.h> 30 3055 danmcd #include <sys/ddi.h> 31 0 stevel #include <sys/strlog.h> 32 0 stevel 33 0 stevel #include <inet/common.h> 34 0 stevel #include <inet/mib2.h> 35 0 stevel #include <inet/ip.h> 36 0 stevel #include <inet/ip6.h> 37 0 stevel 38 0 stevel #include <net/pfkeyv2.h> 39 0 stevel #include <inet/sadb.h> 40 0 stevel #include <inet/ipsec_impl.h> 41 3448 dh155122 #include <inet/ipdrop.h> 42 0 stevel #include <inet/ipsecesp.h> 43 0 stevel #include <inet/ipsecah.h> 44 0 stevel #include <sys/kstat.h> 45 0 stevel 46 0 stevel /* 47 0 stevel * Returns B_TRUE if the identities in the SA match the identities 48 0 stevel * in the "latch" structure. 49 0 stevel */ 50 0 stevel 51 0 stevel static boolean_t 52 0 stevel ipsec_match_outbound_ids(ipsec_latch_t *ipl, ipsa_t *sa) 53 0 stevel { 54 0 stevel ASSERT(ipl->ipl_ids_latched == B_TRUE); 55 0 stevel return ipsid_equal(ipl->ipl_local_cid, sa->ipsa_src_cid) && 56 0 stevel ipsid_equal(ipl->ipl_remote_cid, sa->ipsa_dst_cid); 57 0 stevel } 58 0 stevel 59 11042 Erik /* l1 is packet label; l2 is SA label */ 60 10934 sommerfeld boolean_t 61 11042 Erik ipsec_label_match(ts_label_t *l1, ts_label_t *l2) 62 10934 sommerfeld { 63 10934 sommerfeld if (!is_system_labeled()) 64 10934 sommerfeld return (B_TRUE); 65 10934 sommerfeld 66 10934 sommerfeld /* 67 11042 Erik * Check for NULL label. Unlabeled SA (l2) always matches; 68 10934 sommerfeld * unlabeled user with labeled SA always fails 69 10934 sommerfeld */ 70 11042 Erik if (l2 == NULL) 71 10934 sommerfeld return (B_TRUE); 72 10934 sommerfeld 73 10934 sommerfeld if (l1 == NULL) 74 10934 sommerfeld return (B_FALSE); 75 10934 sommerfeld 76 10934 sommerfeld /* Simple IPsec MLS policy: labels must be equal */ 77 10934 sommerfeld /* In future will need bit in policy saying whether this is the case */ 78 10934 sommerfeld 79 10934 sommerfeld /* 80 10934 sommerfeld * label_equal() checks DOI and label contents. We should be 81 10934 sommerfeld * good to go with this check. 82 10934 sommerfeld */ 83 10934 sommerfeld return (label_equal(l1, l2)); 84 10934 sommerfeld } 85 10934 sommerfeld 86 10934 sommerfeld 87 0 stevel /* 88 0 stevel * Look up a security association based on the unique ID generated by IP and 89 3055 danmcd * transport or tunnel information, such as ports and upper-layer protocol, 90 3055 danmcd * and the inner and outer address(es). Used for uniqueness testing and 91 3055 danmcd * outbound packets. The outer source address may be ignored. 92 0 stevel * 93 0 stevel * I expect an SA hash bucket, and that its per-bucket mutex is held. 94 0 stevel * The SA ptr I return will have its reference count incremented by one. 95 0 stevel */ 96 0 stevel ipsa_t * 97 11042 Erik ipsec_getassocbyconn(isaf_t *bucket, ip_xmit_attr_t *ixa, uint32_t *src, 98 11042 Erik uint32_t *dst, sa_family_t af, uint8_t protocol, ts_label_t *tsl) 99 0 stevel { 100 0 stevel ipsa_t *retval, *candidate; 101 0 stevel ipsec_action_t *candact; 102 0 stevel boolean_t need_unique; 103 11042 Erik boolean_t tunnel_mode = (ixa->ixa_flags & IXAF_IPSEC_TUNNEL); 104 0 stevel uint64_t unique_id; 105 0 stevel uint32_t old_flags, excludeflags; 106 11042 Erik ipsec_policy_t *pp = ixa->ixa_ipsec_policy; 107 11042 Erik ipsec_action_t *actlist = ixa->ixa_ipsec_action; 108 0 stevel ipsec_action_t *act; 109 11042 Erik ipsec_latch_t *ipl = ixa->ixa_ipsec_latch; 110 0 stevel ipsa_ref_t *ipr = NULL; 111 11042 Erik sa_family_t inaf = ixa->ixa_ipsec_inaf; 112 11042 Erik uint32_t *insrc = ixa->ixa_ipsec_insrc; 113 11042 Erik uint32_t *indst = ixa->ixa_ipsec_indst; 114 11042 Erik uint8_t insrcpfx = ixa->ixa_ipsec_insrcpfx; 115 11042 Erik uint8_t indstpfx = ixa->ixa_ipsec_indstpfx; 116 0 stevel 117 0 stevel ASSERT(MUTEX_HELD(&bucket->isaf_lock)); 118 3055 danmcd 119 3055 danmcd /* 120 11042 Erik * Caller must set ip_xmit_attr_t structure such that we know 121 3055 danmcd * whether this is tunnel mode or transport mode based on 122 11042 Erik * IXAF_IPSEC_TUNNEL. If this flag is set, we assume that 123 3055 danmcd * there are valid inner src and destination addresses to compare. 124 3055 danmcd */ 125 0 stevel 126 0 stevel /* 127 0 stevel * Fast path: do we have a latch structure, is it for this bucket, 128 0 stevel * and does the generation number match? If so, refhold and return. 129 0 stevel */ 130 0 stevel 131 0 stevel if (ipl != NULL) { 132 0 stevel ASSERT((protocol == IPPROTO_AH) || (protocol == IPPROTO_ESP)); 133 11042 Erik ipr = &ixa->ixa_ipsec_ref[protocol - IPPROTO_ESP]; 134 0 stevel 135 0 stevel retval = ipr->ipsr_sa; 136 0 stevel 137 0 stevel /* 138 0 stevel * NOTE: The isaf_gen check (incremented upon 139 0 stevel * sadb_unlinkassoc()) protects against retval being a freed 140 0 stevel * SA. (We're exploiting short-circuit evaluation.) 141 0 stevel */ 142 0 stevel if ((bucket == ipr->ipsr_bucket) && 143 0 stevel (bucket->isaf_gen == ipr->ipsr_gen) && 144 0 stevel (retval->ipsa_state != IPSA_STATE_DEAD) && 145 0 stevel !(retval->ipsa_flags & IPSA_F_CINVALID)) { 146 0 stevel IPSA_REFHOLD(retval); 147 0 stevel return (retval); 148 0 stevel } 149 0 stevel } 150 0 stevel 151 0 stevel ASSERT((pp != NULL) || (actlist != NULL)); 152 0 stevel if (actlist == NULL) 153 0 stevel actlist = pp->ipsp_act; 154 0 stevel ASSERT(actlist != NULL); 155 0 stevel 156 0 stevel need_unique = actlist->ipa_want_unique; 157 11042 Erik unique_id = SA_FORM_UNIQUE_ID(ixa); 158 0 stevel 159 0 stevel /* 160 0 stevel * Precompute mask for SA flags comparison: If we need a 161 0 stevel * unique SA and an SA has already been used, or if the SA has 162 0 stevel * a unique value which doesn't match, we aren't interested in 163 0 stevel * the SA.. 164 0 stevel */ 165 0 stevel 166 0 stevel excludeflags = IPSA_F_UNIQUE; 167 0 stevel if (need_unique) 168 0 stevel excludeflags |= IPSA_F_USED; 169 0 stevel 170 0 stevel /* 171 0 stevel * Walk the hash bucket, matching on: 172 0 stevel * 173 0 stevel * - unique_id 174 0 stevel * - destination 175 0 stevel * - source 176 0 stevel * - algorithms 177 3055 danmcd * - inner dst 178 3055 danmcd * - inner src 179 0 stevel * - <MORE TBD> 180 0 stevel * 181 0 stevel * Make sure that wildcard sources are inserted at the end of the hash 182 0 stevel * bucket. 183 0 stevel * 184 0 stevel * DEFINITIONS: A _shared_ SA is one with unique_id == 0 and USED. 185 0 stevel * An _unused_ SA is one with unique_id == 0 and not USED. 186 0 stevel * A _unique_ SA is one with unique_id != 0 and USED. 187 0 stevel * An SA with unique_id != 0 and not USED never happens. 188 0 stevel */ 189 0 stevel 190 0 stevel candidate = NULL; 191 0 stevel 192 0 stevel for (retval = bucket->isaf_ipsa; retval != NULL; 193 0 stevel retval = retval->ipsa_next) { 194 0 stevel ASSERT((candidate == NULL) || 195 0 stevel MUTEX_HELD(&candidate->ipsa_lock)); 196 0 stevel 197 0 stevel /* 198 0 stevel * Q: Should I lock this SA? 199 0 stevel * A: For now, yes. I change and use too many fields in here 200 0 stevel * (e.g. unique_id) that I may be racing with other threads. 201 0 stevel * Also, the refcnt needs to be bumped up. 202 0 stevel */ 203 0 stevel 204 0 stevel mutex_enter(&retval->ipsa_lock); 205 0 stevel 206 0 stevel /* My apologies for the use of goto instead of continue. */ 207 3055 danmcd 208 3055 danmcd /* Outer destination address */ 209 0 stevel if (!IPSA_ARE_ADDR_EQUAL(dst, retval->ipsa_dstaddr, af)) 210 0 stevel goto next_ipsa; /* Destination mismatch. */ 211 3055 danmcd 212 3055 danmcd /* Outer source address */ 213 0 stevel if (!IPSA_ARE_ADDR_EQUAL(src, retval->ipsa_srcaddr, af) && 214 0 stevel !IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af)) 215 0 stevel goto next_ipsa; /* Specific source and not matched. */ 216 3055 danmcd 217 3055 danmcd if (tunnel_mode) { 218 3055 danmcd /* Check tunnel mode */ 219 3055 danmcd if (!(retval->ipsa_flags & IPSA_F_TUNNEL)) 220 3055 danmcd goto next_ipsa; /* Not tunnel mode SA */ 221 3055 danmcd 222 3055 danmcd /* Inner destination address */ 223 3055 danmcd if (!IPSA_IS_ADDR_UNSPEC(retval->ipsa_innerdst, inaf)) { 224 3055 danmcd if (!ip_addr_match((uint8_t *)indst, 225 3055 danmcd min(indstpfx, retval->ipsa_innerdstpfx), 226 3055 danmcd (in6_addr_t *)retval->ipsa_innerdst)) 227 3055 danmcd goto next_ipsa; /* not matched. */ 228 3055 danmcd } 229 3055 danmcd 230 3055 danmcd /* Inner source address */ 231 3055 danmcd if (!IPSA_IS_ADDR_UNSPEC(retval->ipsa_innersrc, inaf)) { 232 3055 danmcd if (!ip_addr_match((uint8_t *)insrc, 233 3055 danmcd min(insrcpfx, retval->ipsa_innersrcpfx), 234 3055 danmcd (in6_addr_t *)retval->ipsa_innersrc)) 235 3055 danmcd goto next_ipsa; /* not matched. */ 236 3055 danmcd } 237 3055 danmcd } else { 238 3055 danmcd /* Check transport mode */ 239 3055 danmcd if (retval->ipsa_flags & IPSA_F_TUNNEL) 240 3055 danmcd goto next_ipsa; /* Not transport mode SA */ 241 3055 danmcd 242 3055 danmcd /* 243 3055 danmcd * TODO - If we ever do RFC 3884's dream of transport- 244 3055 danmcd * mode SAs with inner IP address selectors, we need 245 3055 danmcd * to put some code here. 246 3055 danmcd */ 247 3055 danmcd } 248 0 stevel 249 0 stevel /* 250 0 stevel * XXX should be able to use cached/latched action 251 0 stevel * to dodge this loop 252 0 stevel */ 253 0 stevel for (act = actlist; act != NULL; act = act->ipa_next) { 254 0 stevel ipsec_act_t *ap = &act->ipa_act; 255 0 stevel if (ap->ipa_type != IPSEC_POLICY_APPLY) 256 0 stevel continue; 257 0 stevel 258 0 stevel /* 259 0 stevel * XXX ugly. should be better way to do this test 260 0 stevel */ 261 0 stevel if (protocol == IPPROTO_AH) { 262 0 stevel if (!(ap->ipa_apply.ipp_use_ah)) 263 0 stevel continue; 264 0 stevel if (ap->ipa_apply.ipp_auth_alg != 265 0 stevel retval->ipsa_auth_alg) 266 0 stevel continue; 267 0 stevel if (ap->ipa_apply.ipp_ah_minbits > 268 7749 Thejaswini retval->ipsa_authkeybits) 269 0 stevel continue; 270 0 stevel } else { 271 0 stevel if (!(ap->ipa_apply.ipp_use_esp)) 272 0 stevel continue; 273 0 stevel 274 0 stevel if ((ap->ipa_apply.ipp_encr_alg != 275 0 stevel retval->ipsa_encr_alg)) 276 0 stevel continue; 277 0 stevel 278 0 stevel if (ap->ipa_apply.ipp_espe_minbits > 279 0 stevel retval->ipsa_encrkeybits) 280 0 stevel continue; 281 0 stevel 282 0 stevel if (ap->ipa_apply.ipp_esp_auth_alg != 0) { 283 0 stevel if (ap->ipa_apply.ipp_esp_auth_alg != 284 0 stevel retval->ipsa_auth_alg) 285 0 stevel continue; 286 0 stevel if (ap->ipa_apply.ipp_espa_minbits > 287 0 stevel retval->ipsa_authkeybits) 288 0 stevel continue; 289 0 stevel } 290 0 stevel } 291 0 stevel 292 0 stevel /* 293 0 stevel * Check key mgmt proto, cookie 294 0 stevel */ 295 0 stevel if ((ap->ipa_apply.ipp_km_proto != 0) && 296 0 stevel (retval->ipsa_kmp != 0) && 297 0 stevel (ap->ipa_apply.ipp_km_proto != retval->ipsa_kmp)) 298 0 stevel continue; 299 0 stevel 300 0 stevel if ((ap->ipa_apply.ipp_km_cookie != 0) && 301 0 stevel (retval->ipsa_kmc != 0) && 302 0 stevel (ap->ipa_apply.ipp_km_cookie != retval->ipsa_kmc)) 303 0 stevel continue; 304 0 stevel 305 0 stevel break; 306 0 stevel } 307 0 stevel if (act == NULL) 308 0 stevel goto next_ipsa; /* nothing matched */ 309 0 stevel 310 0 stevel /* 311 0 stevel * Do identities match? 312 0 stevel */ 313 0 stevel if (ipl && ipl->ipl_ids_latched && 314 0 stevel !ipsec_match_outbound_ids(ipl, retval)) 315 10934 sommerfeld goto next_ipsa; 316 10934 sommerfeld 317 10934 sommerfeld /* 318 10934 sommerfeld * Do labels match? 319 10934 sommerfeld */ 320 11042 Erik if (!ipsec_label_match(tsl, retval->ipsa_tsl)) 321 0 stevel goto next_ipsa; 322 0 stevel 323 0 stevel /* 324 0 stevel * At this point, we know that we have at least a match on: 325 0 stevel * 326 0 stevel * - dest 327 0 stevel * - source (if source is specified, i.e. non-zeroes) 328 3055 danmcd * - inner dest (if specified) 329 3055 danmcd * - inner source (if specified) 330 0 stevel * - auth alg (if auth alg is specified, i.e. non-zero) 331 0 stevel * - encrypt. alg (if encrypt. alg is specified, i.e. non-zero) 332 0 stevel * and we know that the SA keylengths are appropriate. 333 0 stevel * 334 0 stevel * (Keep in mind known-src SAs are hit before zero-src SAs, 335 0 stevel * thanks to sadb_insertassoc().) 336 0 stevel * If we need a unique asssociation, optimally we have 337 0 stevel * ipsa_unique_id == unique_id, otherwise NOT USED 338 0 stevel * is held in reserve (stored in candidate). 339 0 stevel * 340 0 stevel * For those stored in candidate, take best-match (i.e. given 341 0 stevel * a choice, candidate should have non-zero ipsa_src). 342 0 stevel */ 343 0 stevel 344 0 stevel /* 345 0 stevel * If SA has a unique value which matches, we're all set... 346 0 stevel * "key management knows best" 347 0 stevel */ 348 0 stevel if ((retval->ipsa_flags & IPSA_F_UNIQUE) && 349 0 stevel ((unique_id & retval->ipsa_unique_mask) == 350 7749 Thejaswini retval->ipsa_unique_id)) 351 0 stevel break; 352 0 stevel 353 0 stevel /* 354 0 stevel * If we need a unique SA and this SA has already been used, 355 0 stevel * or if the SA has a unique value which doesn't match, 356 0 stevel * this isn't for us. 357 0 stevel */ 358 0 stevel 359 0 stevel if (retval->ipsa_flags & excludeflags) 360 0 stevel goto next_ipsa; 361 0 stevel 362 0 stevel 363 0 stevel /* 364 0 stevel * I found a candidate.. 365 0 stevel */ 366 0 stevel if (candidate == NULL) { 367 0 stevel /* 368 0 stevel * and didn't already have one.. 369 0 stevel */ 370 0 stevel candidate = retval; 371 0 stevel candact = act; 372 0 stevel continue; 373 0 stevel } else { 374 0 stevel /* 375 0 stevel * If candidate's source address is zero and 376 0 stevel * the current match (i.e. retval) address is 377 0 stevel * not zero, we have a better candidate.. 378 0 stevel */ 379 0 stevel if (IPSA_IS_ADDR_UNSPEC(candidate->ipsa_srcaddr, af) && 380 0 stevel !IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af)) { 381 0 stevel mutex_exit(&candidate->ipsa_lock); 382 0 stevel candidate = retval; 383 0 stevel candact = act; 384 0 stevel continue; 385 0 stevel } 386 0 stevel } 387 0 stevel next_ipsa: 388 0 stevel mutex_exit(&retval->ipsa_lock); 389 0 stevel } 390 0 stevel ASSERT((retval == NULL) || MUTEX_HELD(&retval->ipsa_lock)); 391 0 stevel ASSERT((candidate == NULL) || MUTEX_HELD(&candidate->ipsa_lock)); 392 0 stevel ASSERT((retval == NULL) || (act != NULL)); 393 0 stevel ASSERT((candidate == NULL) || (candact != NULL)); 394 0 stevel 395 0 stevel /* Let caller react to a lookup failure when it gets NULL. */ 396 0 stevel if (retval == NULL && candidate == NULL) 397 0 stevel return (NULL); 398 0 stevel 399 0 stevel if (retval == NULL) { 400 0 stevel ASSERT(MUTEX_HELD(&candidate->ipsa_lock)); 401 0 stevel retval = candidate; 402 0 stevel act = candact; 403 0 stevel } else if (candidate != NULL) { 404 0 stevel mutex_exit(&candidate->ipsa_lock); 405 0 stevel } 406 0 stevel ASSERT(MUTEX_HELD(&retval->ipsa_lock)); 407 0 stevel ASSERT(act != NULL); 408 0 stevel 409 0 stevel /* 410 0 stevel * Even though I hold the mutex, since the reference counter is an 411 0 stevel * atomic operation, I really have to use the IPSA_REFHOLD macro. 412 0 stevel */ 413 0 stevel IPSA_REFHOLD(retval); 414 0 stevel 415 0 stevel /* 416 0 stevel * This association is no longer unused. 417 0 stevel */ 418 0 stevel old_flags = retval->ipsa_flags; 419 0 stevel retval->ipsa_flags |= IPSA_F_USED; 420 0 stevel 421 0 stevel /* 422 0 stevel * Cache a reference to this SA for the fast path. 423 0 stevel */ 424 0 stevel if (ipr != NULL) { 425 0 stevel ipr->ipsr_bucket = bucket; 426 0 stevel ipr->ipsr_gen = bucket->isaf_gen; 427 0 stevel ipr->ipsr_sa = retval; 428 0 stevel /* I'm now caching, so the cache-invalid flag goes away! */ 429 0 stevel retval->ipsa_flags &= ~IPSA_F_CINVALID; 430 0 stevel } 431 0 stevel /* 432 0 stevel * Latch various things while we're here.. 433 0 stevel */ 434 0 stevel if (ipl != NULL) { 435 0 stevel if (!ipl->ipl_ids_latched) { 436 0 stevel ipsec_latch_ids(ipl, 437 0 stevel retval->ipsa_src_cid, retval->ipsa_dst_cid); 438 0 stevel } 439 11042 Erik if (ixa->ixa_ipsec_action == NULL) { 440 0 stevel IPACT_REFHOLD(act); 441 11042 Erik ixa->ixa_ipsec_action = act; 442 0 stevel } 443 0 stevel } 444 0 stevel 445 0 stevel /* 446 0 stevel * Set the uniqueness only first time. 447 0 stevel */ 448 0 stevel if (need_unique && !(old_flags & IPSA_F_USED)) { 449 0 stevel if (retval->ipsa_unique_id == 0) { 450 0 stevel ASSERT((retval->ipsa_flags & IPSA_F_UNIQUE) == 0); 451 0 stevel /* 452 0 stevel * From now on, only this src, dst[ports, addr], 453 0 stevel * proto, should use it. 454 0 stevel */ 455 0 stevel retval->ipsa_flags |= IPSA_F_UNIQUE; 456 0 stevel retval->ipsa_unique_id = unique_id; 457 0 stevel retval->ipsa_unique_mask = SA_UNIQUE_MASK( 458 11042 Erik ixa->ixa_ipsec_src_port, ixa->ixa_ipsec_dst_port, 459 3055 danmcd protocol, 0); 460 0 stevel } 461 0 stevel 462 0 stevel /* 463 0 stevel * Set the source address and adjust the hash 464 0 stevel * buckets only if src_addr is zero. 465 0 stevel */ 466 0 stevel if (IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af)) { 467 0 stevel /* 468 0 stevel * sadb_unlinkassoc() will decrement the refcnt. Bump 469 0 stevel * up when we have the lock so that we don't have to 470 0 stevel * acquire locks when we come back from 471 0 stevel * sadb_insertassoc(). 472 0 stevel * 473 0 stevel * We don't need to bump the bucket's gen since 474 0 stevel * we aren't moving to a new bucket. 475 0 stevel */ 476 0 stevel IPSA_REFHOLD(retval); 477 0 stevel IPSA_COPY_ADDR(retval->ipsa_srcaddr, src, af); 478 0 stevel mutex_exit(&retval->ipsa_lock); 479 0 stevel sadb_unlinkassoc(retval); 480 0 stevel /* 481 0 stevel * Since the bucket lock is held, we know 482 0 stevel * sadb_insertassoc() will succeed. 483 0 stevel */ 484 0 stevel #ifdef DEBUG 485 0 stevel if (sadb_insertassoc(retval, bucket) != 0) { 486 0 stevel cmn_err(CE_PANIC, 487 0 stevel "sadb_insertassoc() failed in " 488 0 stevel "ipsec_getassocbyconn().\n"); 489 0 stevel } 490 0 stevel #else /* non-DEBUG */ 491 0 stevel (void) sadb_insertassoc(retval, bucket); 492 0 stevel #endif /* DEBUG */ 493 0 stevel return (retval); 494 0 stevel } 495 0 stevel } 496 0 stevel mutex_exit(&retval->ipsa_lock); 497 0 stevel 498 0 stevel return (retval); 499 0 stevel } 500 0 stevel 501 0 stevel /* 502 0 stevel * Look up a security association based on the security parameters index (SPI) 503 0 stevel * and address(es). This is used for inbound packets and general SA lookups 504 0 stevel * (even in outbound SA tables). The source address may be ignored. Return 505 0 stevel * NULL if no association is available. If an SA is found, return it, with 506 0 stevel * its refcnt incremented. The caller must REFRELE after using the SA. 507 0 stevel * The hash bucket must be locked down before calling. 508 0 stevel */ 509 0 stevel ipsa_t * 510 0 stevel ipsec_getassocbyspi(isaf_t *bucket, uint32_t spi, uint32_t *src, uint32_t *dst, 511 0 stevel sa_family_t af) 512 0 stevel { 513 0 stevel ipsa_t *retval; 514 0 stevel 515 0 stevel ASSERT(MUTEX_HELD(&bucket->isaf_lock)); 516 0 stevel 517 0 stevel /* 518 0 stevel * Walk the hash bucket, matching exactly on SPI, then destination, 519 0 stevel * then source. 520 0 stevel * 521 0 stevel * Per-SA locking doesn't need to happen, because I'm only matching 522 0 stevel * on addresses. Addresses are only changed during insertion/deletion 523 0 stevel * from the hash bucket. Since the hash bucket lock is held, we don't 524 0 stevel * need to worry about addresses changing. 525 0 stevel */ 526 0 stevel 527 0 stevel for (retval = bucket->isaf_ipsa; retval != NULL; 528 0 stevel retval = retval->ipsa_next) { 529 0 stevel if (retval->ipsa_spi != spi) 530 0 stevel continue; 531 0 stevel if (!IPSA_ARE_ADDR_EQUAL(dst, retval->ipsa_dstaddr, af)) 532 0 stevel continue; 533 0 stevel 534 0 stevel /* 535 0 stevel * Assume that wildcard source addresses are inserted at the 536 0 stevel * end of the hash bucket. (See sadb_insertassoc().) 537 0 stevel * The following check for source addresses is a weak form 538 0 stevel * of access control/source identity verification. If an 539 0 stevel * SA has a source address, I only match an all-zeroes 540 0 stevel * source address, or that particular one. If the SA has 541 0 stevel * an all-zeroes source, then I match regardless. 542 0 stevel * 543 0 stevel * There is a weakness here in that a packet with all-zeroes 544 0 stevel * for an address will match regardless of the source address 545 0 stevel * stored in the packet. 546 691 sommerfe * 547 691 sommerfe * Note that port-level packet selectors, if present, 548 691 sommerfe * are checked in ipsec_check_ipsecin_unique(). 549 0 stevel */ 550 0 stevel if (IPSA_ARE_ADDR_EQUAL(src, retval->ipsa_srcaddr, af) || 551 0 stevel IPSA_IS_ADDR_UNSPEC(retval->ipsa_srcaddr, af) || 552 0 stevel IPSA_IS_ADDR_UNSPEC(src, af)) 553 0 stevel break; 554 0 stevel } 555 0 stevel 556 0 stevel if (retval != NULL) { 557 0 stevel /* 558 0 stevel * Just refhold the return value. The caller will then 559 0 stevel * make the appropriate calls to set the USED flag. 560 0 stevel */ 561 0 stevel IPSA_REFHOLD(retval); 562 0 stevel } 563 0 stevel 564 0 stevel return (retval); 565 0 stevel } 566 0 stevel 567 0 stevel boolean_t 568 11042 Erik ipsec_outbound_sa(mblk_t *data_mp, ip_xmit_attr_t *ixa, uint_t proto) 569 0 stevel { 570 0 stevel ipaddr_t dst; 571 0 stevel uint32_t *dst_ptr, *src_ptr; 572 0 stevel isaf_t *bucket; 573 0 stevel ipsa_t *assoc; 574 11042 Erik ip_pkt_t ipp; 575 0 stevel in6_addr_t dst6; 576 0 stevel ipsa_t **sa; 577 0 stevel sadbp_t *sadbp; 578 564 sommerfe sadb_t *sp; 579 0 stevel sa_family_t af; 580 11042 Erik ip_stack_t *ipst = ixa->ixa_ipst; 581 11042 Erik netstack_t *ns = ipst->ips_netstack; 582 0 stevel 583 11042 Erik ASSERT(ixa->ixa_flags & IXAF_IPSEC_SECURE); 584 0 stevel 585 0 stevel if (proto == IPPROTO_ESP) { 586 3448 dh155122 ipsecesp_stack_t *espstack; 587 3448 dh155122 588 3448 dh155122 espstack = ns->netstack_ipsecesp; 589 11042 Erik sa = &ixa->ixa_ipsec_esp_sa; 590 3448 dh155122 sadbp = &espstack->esp_sadb; 591 0 stevel } else { 592 3448 dh155122 ipsecah_stack_t *ahstack; 593 3448 dh155122 594 0 stevel ASSERT(proto == IPPROTO_AH); 595 3448 dh155122 ahstack = ns->netstack_ipsecah; 596 11042 Erik sa = &ixa->ixa_ipsec_ah_sa; 597 3448 dh155122 sadbp = &ahstack->ah_sadb; 598 0 stevel } 599 0 stevel 600 0 stevel ASSERT(*sa == NULL); 601 0 stevel 602 11042 Erik if (ixa->ixa_flags & IXAF_IS_IPV4) { 603 0 stevel ipha_t *ipha = (ipha_t *)data_mp->b_rptr; 604 0 stevel 605 0 stevel ASSERT(IPH_HDR_VERSION(ipha) == IPV4_VERSION); 606 0 stevel dst = ip_get_dst(ipha); 607 564 sommerfe sp = &sadbp->s_v4; 608 0 stevel af = AF_INET; 609 0 stevel 610 0 stevel /* 611 0 stevel * NOTE:Getting the outbound association is considerably 612 0 stevel * painful. ipsec_getassocbyconn() will require more 613 0 stevel * parameters as policy implementations mature. 614 0 stevel */ 615 564 sommerfe bucket = OUTBOUND_BUCKET_V4(sp, dst); 616 0 stevel src_ptr = (uint32_t *)&ipha->ipha_src; 617 0 stevel dst_ptr = (uint32_t *)&dst; 618 0 stevel } else { 619 0 stevel ip6_t *ip6h = (ip6_t *)data_mp->b_rptr; 620 0 stevel 621 0 stevel ASSERT(IPH_HDR_VERSION(ip6h) == IPV6_VERSION); 622 8705 danmcd dst6 = ip_get_dst_v6(ip6h, data_mp, NULL); 623 0 stevel af = AF_INET6; 624 0 stevel 625 0 stevel bzero(&ipp, sizeof (ipp)); 626 564 sommerfe sp = &sadbp->s_v6; 627 0 stevel 628 0 stevel /* Same NOTE: applies here! */ 629 564 sommerfe bucket = OUTBOUND_BUCKET_V6(sp, dst6); 630 0 stevel src_ptr = (uint32_t *)&ip6h->ip6_src; 631 0 stevel dst_ptr = (uint32_t *)&dst6; 632 0 stevel } 633 0 stevel 634 0 stevel mutex_enter(&bucket->isaf_lock); 635 11042 Erik assoc = ipsec_getassocbyconn(bucket, ixa, src_ptr, dst_ptr, af, 636 11042 Erik proto, ixa->ixa_tsl); 637 0 stevel mutex_exit(&bucket->isaf_lock); 638 0 stevel 639 0 stevel if (assoc == NULL) 640 0 stevel return (B_FALSE); 641 0 stevel 642 0 stevel if (assoc->ipsa_state == IPSA_STATE_DEAD) { 643 0 stevel IPSA_REFRELE(assoc); 644 0 stevel return (B_FALSE); 645 0 stevel } 646 0 stevel 647 0 stevel ASSERT(assoc->ipsa_state != IPSA_STATE_LARVAL); 648 0 stevel 649 0 stevel *sa = assoc; 650 0 stevel return (B_TRUE); 651 0 stevel } 652 0 stevel 653 0 stevel /* 654 0 stevel * Inbound IPsec SA selection. 655 11042 Erik * Can return a pulled up mblk. 656 11042 Erik * When it returns non-NULL ahp is updated 657 0 stevel */ 658 11042 Erik mblk_t * 659 11042 Erik ipsec_inbound_ah_sa(mblk_t *mp, ip_recv_attr_t *ira, ah_t **ahp) 660 0 stevel { 661 0 stevel ipha_t *ipha; 662 0 stevel ipsa_t *assoc; 663 0 stevel ah_t *ah; 664 0 stevel isaf_t *hptr; 665 0 stevel boolean_t isv6; 666 0 stevel ip6_t *ip6h; 667 0 stevel int ah_offset; 668 0 stevel uint32_t *src_ptr, *dst_ptr; 669 0 stevel int pullup_len; 670 564 sommerfe sadb_t *sp; 671 0 stevel sa_family_t af; 672 11042 Erik netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack; 673 3448 dh155122 ipsec_stack_t *ipss = ns->netstack_ipsec; 674 3448 dh155122 ipsecah_stack_t *ahstack = ns->netstack_ipsecah; 675 0 stevel 676 3448 dh155122 IP_AH_BUMP_STAT(ipss, in_requests); 677 0 stevel 678 11042 Erik isv6 = !(ira->ira_flags & IRAF_IS_IPV4); 679 0 stevel if (isv6) { 680 0 stevel ip6h = (ip6_t *)mp->b_rptr; 681 0 stevel ah_offset = ipsec_ah_get_hdr_size_v6(mp, B_TRUE); 682 0 stevel } else { 683 0 stevel ipha = (ipha_t *)mp->b_rptr; 684 0 stevel ASSERT(ipha->ipha_protocol == IPPROTO_AH); 685 0 stevel ah_offset = ipha->ipha_version_and_hdr_length - 686 0 stevel (uint8_t)((IP_VERSION << 4)); 687 0 stevel ah_offset <<= 2; 688 0 stevel } 689 0 stevel 690 0 stevel /* 691 0 stevel * We assume that the IP header is pulled up until 692 0 stevel * the options. We need to see whether we have the 693 0 stevel * AH header in the same mblk or not. 694 0 stevel */ 695 0 stevel pullup_len = ah_offset + sizeof (ah_t); 696 0 stevel if (mp->b_rptr + pullup_len > mp->b_wptr) { 697 0 stevel if (!pullupmsg(mp, pullup_len)) { 698 3448 dh155122 ipsec_rl_strlog(ns, ip_mod_info.mi_idnum, 0, 0, 699 1659 markfen SL_WARN | SL_ERROR, 700 0 stevel "ipsec_inbound_ah_sa: Small AH header\n"); 701 3448 dh155122 IP_AH_BUMP_STAT(ipss, in_discards); 702 11042 Erik ip_drop_packet(mp, B_TRUE, ira->ira_ill, 703 3448 dh155122 DROPPER(ipss, ipds_ah_bad_length), 704 3448 dh155122 &ipss->ipsec_dropper); 705 0 stevel return (NULL); 706 0 stevel } 707 0 stevel if (isv6) 708 0 stevel ip6h = (ip6_t *)mp->b_rptr; 709 0 stevel else 710 0 stevel ipha = (ipha_t *)mp->b_rptr; 711 0 stevel } 712 0 stevel 713 0 stevel ah = (ah_t *)(mp->b_rptr + ah_offset); 714 0 stevel 715 0 stevel if (isv6) { 716 0 stevel src_ptr = (uint32_t *)&ip6h->ip6_src; 717 0 stevel dst_ptr = (uint32_t *)&ip6h->ip6_dst; 718 3448 dh155122 sp = &ahstack->ah_sadb.s_v6; 719 0 stevel af = AF_INET6; 720 0 stevel } else { 721 0 stevel src_ptr = (uint32_t *)&ipha->ipha_src; 722 0 stevel dst_ptr = (uint32_t *)&ipha->ipha_dst; 723 3448 dh155122 sp = &ahstack->ah_sadb.s_v4; 724 0 stevel af = AF_INET; 725 0 stevel } 726 0 stevel 727 564 sommerfe hptr = INBOUND_BUCKET(sp, ah->ah_spi); 728 0 stevel mutex_enter(&hptr->isaf_lock); 729 0 stevel assoc = ipsec_getassocbyspi(hptr, ah->ah_spi, src_ptr, dst_ptr, af); 730 0 stevel mutex_exit(&hptr->isaf_lock); 731 0 stevel 732 7749 Thejaswini if (assoc == NULL || assoc->ipsa_state == IPSA_STATE_DEAD || 733 7749 Thejaswini assoc->ipsa_state == IPSA_STATE_ACTIVE_ELSEWHERE) { 734 3448 dh155122 IP_AH_BUMP_STAT(ipss, lookup_failure); 735 3448 dh155122 IP_AH_BUMP_STAT(ipss, in_discards); 736 11042 Erik ipsecah_in_assocfailure(mp, 0, 737 0 stevel SL_ERROR | SL_CONSOLE | SL_WARN, 738 0 stevel "ipsec_inbound_ah_sa: No association found for " 739 0 stevel "spi 0x%x, dst addr %s\n", 740 11042 Erik ah->ah_spi, dst_ptr, af, ira); 741 0 stevel if (assoc != NULL) { 742 0 stevel IPSA_REFRELE(assoc); 743 0 stevel } 744 0 stevel return (NULL); 745 0 stevel } 746 0 stevel 747 8185 danmcd if (assoc->ipsa_state == IPSA_STATE_LARVAL && 748 11042 Erik sadb_set_lpkt(assoc, mp, ira)) { 749 0 stevel /* Not fully baked; swap the packet under a rock until then */ 750 0 stevel IPSA_REFRELE(assoc); 751 0 stevel return (NULL); 752 11042 Erik } 753 11042 Erik 754 11042 Erik /* Are the IPsec fields initialized at all? */ 755 11042 Erik if (!(ira->ira_flags & IRAF_IPSEC_SECURE)) { 756 11042 Erik ira->ira_ipsec_action = NULL; 757 11042 Erik ira->ira_ipsec_ah_sa = NULL; 758 11042 Erik ira->ira_ipsec_esp_sa = NULL; 759 0 stevel } 760 0 stevel 761 0 stevel /* 762 0 stevel * Save a reference to the association so that it can 763 0 stevel * be retrieved after execution. We free any AH SA reference 764 0 stevel * already there (innermost SA "wins". The reference to 765 0 stevel * the SA will also be used later when doing the policy checks. 766 0 stevel */ 767 11042 Erik if (ira->ira_ipsec_ah_sa != NULL) { 768 11042 Erik IPSA_REFRELE(ira->ira_ipsec_ah_sa); 769 11042 Erik } 770 11042 Erik ira->ira_flags |= IRAF_IPSEC_SECURE; 771 11042 Erik ira->ira_ipsec_ah_sa = assoc; 772 7749 Thejaswini 773 11042 Erik *ahp = ah; 774 11042 Erik return (mp); 775 0 stevel } 776 0 stevel 777 11042 Erik /* 778 11042 Erik * Can return a pulled up mblk. 779 11042 Erik * When it returns non-NULL esphp is updated 780 11042 Erik */ 781 11042 Erik mblk_t * 782 11042 Erik ipsec_inbound_esp_sa(mblk_t *data_mp, ip_recv_attr_t *ira, esph_t **esphp) 783 0 stevel { 784 11042 Erik mblk_t *placeholder; 785 0 stevel uint32_t *src_ptr, *dst_ptr; 786 0 stevel ipha_t *ipha; 787 0 stevel ip6_t *ip6h; 788 0 stevel esph_t *esph; 789 0 stevel ipsa_t *ipsa; 790 0 stevel isaf_t *bucket; 791 0 stevel uint_t preamble; 792 0 stevel sa_family_t af; 793 0 stevel boolean_t isv6; 794 564 sommerfe sadb_t *sp; 795 11042 Erik netstack_t *ns = ira->ira_ill->ill_ipst->ips_netstack; 796 3448 dh155122 ipsec_stack_t *ipss = ns->netstack_ipsec; 797 3448 dh155122 ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; 798 0 stevel 799 3448 dh155122 IP_ESP_BUMP_STAT(ipss, in_requests); 800 0 stevel 801 11042 Erik isv6 = !(ira->ira_flags & IRAF_IS_IPV4); 802 0 stevel if (isv6) { 803 0 stevel ip6h = (ip6_t *)data_mp->b_rptr; 804 0 stevel } else { 805 0 stevel ipha = (ipha_t *)data_mp->b_rptr; 806 0 stevel } 807 0 stevel 808 0 stevel /* 809 0 stevel * Put all data into one mblk if it's not there already. 810 0 stevel * XXX This is probably bad long-term. Figure out better ways of doing 811 0 stevel * this. Much of the inbound path depends on all of the data being 812 0 stevel * in one mblk. 813 0 stevel * 814 0 stevel * XXX Jumbogram issues will have to be dealt with here. 815 0 stevel * If the plen is 0, we'll have to scan for a HBH header with the 816 0 stevel * actual packet length. 817 0 stevel */ 818 0 stevel if (data_mp->b_datap->db_ref > 1 || 819 11042 Erik (data_mp->b_wptr - data_mp->b_rptr) < ira->ira_pktlen) { 820 0 stevel placeholder = msgpullup(data_mp, -1); 821 0 stevel if (placeholder == NULL) { 822 3448 dh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 823 11042 Erik ip_drop_packet(data_mp, B_TRUE, ira->ira_ill, 824 3448 dh155122 DROPPER(ipss, ipds_esp_nomem), 825 3448 dh155122 &ipss->ipsec_dropper); 826 0 stevel return (NULL); 827 0 stevel } else { 828 0 stevel /* Reset packet with new pulled up mblk. */ 829 0 stevel freemsg(data_mp); 830 0 stevel data_mp = placeholder; 831 0 stevel } 832 0 stevel } 833 0 stevel 834 0 stevel /* 835 0 stevel * Find the ESP header, point the address pointers at the appropriate 836 0 stevel * IPv4/IPv6 places. 837 0 stevel */ 838 0 stevel if (isv6) { 839 0 stevel ip6h = (ip6_t *)data_mp->b_rptr; 840 0 stevel src_ptr = (uint32_t *)&ip6h->ip6_src; 841 0 stevel dst_ptr = (uint32_t *)&ip6h->ip6_dst; 842 0 stevel if (ip6h->ip6_nxt != IPPROTO_ESP) { 843 0 stevel /* There are options that need to be processed. */ 844 0 stevel preamble = ip_hdr_length_v6(data_mp, ip6h); 845 0 stevel } else { 846 0 stevel preamble = sizeof (ip6_t); 847 0 stevel } 848 0 stevel 849 3448 dh155122 sp = &espstack->esp_sadb.s_v6; 850 0 stevel af = AF_INET6; 851 0 stevel } else { 852 0 stevel ipha = (ipha_t *)data_mp->b_rptr; 853 0 stevel src_ptr = (uint32_t *)&ipha->ipha_src; 854 0 stevel dst_ptr = (uint32_t *)&ipha->ipha_dst; 855 0 stevel preamble = IPH_HDR_LENGTH(ipha); 856 0 stevel 857 3448 dh155122 sp = &espstack->esp_sadb.s_v4; 858 0 stevel af = AF_INET; 859 0 stevel } 860 0 stevel 861 0 stevel esph = (esph_t *)(data_mp->b_rptr + preamble); 862 0 stevel 863 0 stevel /* Since hash is common on inbound (SPI value), hash here. */ 864 564 sommerfe bucket = INBOUND_BUCKET(sp, esph->esph_spi); 865 0 stevel mutex_enter(&bucket->isaf_lock); 866 0 stevel ipsa = ipsec_getassocbyspi(bucket, esph->esph_spi, src_ptr, dst_ptr, 867 0 stevel af); 868 0 stevel mutex_exit(&bucket->isaf_lock); 869 0 stevel 870 7749 Thejaswini if (ipsa == NULL || ipsa->ipsa_state == IPSA_STATE_DEAD || 871 7749 Thejaswini ipsa->ipsa_state == IPSA_STATE_ACTIVE_ELSEWHERE) { 872 0 stevel /* This is a loggable error! AUDIT ME! */ 873 3448 dh155122 IP_ESP_BUMP_STAT(ipss, lookup_failure); 874 3448 dh155122 IP_ESP_BUMP_STAT(ipss, in_discards); 875 11042 Erik ipsecesp_in_assocfailure(data_mp, 0, 876 0 stevel SL_ERROR | SL_CONSOLE | SL_WARN, 877 0 stevel "ipsec_inbound_esp_sa: No association found for " 878 0 stevel "spi 0x%x, dst addr %s\n", 879 11042 Erik esph->esph_spi, dst_ptr, af, ira); 880 0 stevel if (ipsa != NULL) { 881 0 stevel IPSA_REFRELE(ipsa); 882 0 stevel } 883 0 stevel return (NULL); 884 0 stevel } 885 0 stevel 886 8185 danmcd if (ipsa->ipsa_state == IPSA_STATE_LARVAL && 887 11042 Erik sadb_set_lpkt(ipsa, data_mp, ira)) { 888 0 stevel /* Not fully baked; swap the packet under a rock until then */ 889 0 stevel IPSA_REFRELE(ipsa); 890 0 stevel return (NULL); 891 11042 Erik } 892 11042 Erik 893 11042 Erik /* Are the IPsec fields initialized at all? */ 894 11042 Erik if (!(ira->ira_flags & IRAF_IPSEC_SECURE)) { 895 11042 Erik ira->ira_ipsec_action = NULL; 896 11042 Erik ira->ira_ipsec_ah_sa = NULL; 897 11042 Erik ira->ira_ipsec_esp_sa = NULL; 898 0 stevel } 899 0 stevel 900 0 stevel /* 901 0 stevel * Save a reference to the association so that it can 902 0 stevel * be retrieved after execution. We free any AH SA reference 903 0 stevel * already there (innermost SA "wins". The reference to 904 0 stevel * the SA will also be used later when doing the policy checks. 905 0 stevel */ 906 11042 Erik if (ira->ira_ipsec_esp_sa != NULL) { 907 11042 Erik IPSA_REFRELE(ira->ira_ipsec_esp_sa); 908 0 stevel } 909 11042 Erik ira->ira_flags |= IRAF_IPSEC_SECURE; 910 11042 Erik ira->ira_ipsec_esp_sa = ipsa; 911 0 stevel 912 11042 Erik *esphp = esph; 913 11042 Erik return (data_mp); 914 0 stevel } 915