1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/stream.h> 30 #include <sys/stropts.h> 31 #include <sys/errno.h> 32 #include <sys/strlog.h> 33 #include <sys/tihdr.h> 34 #include <sys/socket.h> 35 #include <sys/ddi.h> 36 #include <sys/sunddi.h> 37 #include <sys/kmem.h> 38 #include <sys/cmn_err.h> 39 #include <sys/vtrace.h> 40 #include <sys/debug.h> 41 #include <sys/atomic.h> 42 #include <sys/strsun.h> 43 #include <sys/random.h> 44 #include <netinet/in.h> 45 #include <net/if.h> 46 #include <netinet/ip6.h> 47 #include <netinet/icmp6.h> 48 #include <net/pfkeyv2.h> 49 50 #include <inet/common.h> 51 #include <inet/mi.h> 52 #include <inet/ip.h> 53 #include <inet/ip6.h> 54 #include <inet/nd.h> 55 #include <inet/ipsec_info.h> 56 #include <inet/ipsec_impl.h> 57 #include <inet/sadb.h> 58 #include <inet/ipsecah.h> 59 #include <inet/ipsec_impl.h> 60 #include <inet/ipdrop.h> 61 #include <sys/taskq.h> 62 #include <sys/policy.h> 63 #include <sys/iphada.h> 64 #include <sys/strsun.h> 65 66 #include <sys/crypto/common.h> 67 #include <sys/crypto/api.h> 68 #include <sys/kstat.h> 69 70 /* Packet dropper for AH drops. */ 71 static ipdropper_t ah_dropper; 72 73 static kmutex_t ipsecah_param_lock; /* Protect ipsecah_param_arr[] below. */ 74 /* 75 * Table of ND variables supported by ipsecah. These are loaded into 76 * ipsecah_g_nd in ipsecah_init_nd. 77 * All of these are alterable, within the min/max values given, at run time. 78 */ 79 static ipsecahparam_t ipsecah_param_arr[] = { 80 /* min max value name */ 81 { 0, 3, 0, "ipsecah_debug"}, 82 { 125, 32000, SADB_AGE_INTERVAL_DEFAULT, "ipsecah_age_interval"}, 83 { 1, 10, 1, "ipsecah_reap_delay"}, 84 { 1, SADB_MAX_REPLAY, 64, "ipsecah_replay_size"}, 85 { 1, 300, 15, "ipsecah_acquire_timeout"}, 86 { 1, 1800, 90, "ipsecah_larval_timeout"}, 87 /* Default lifetime values for ACQUIRE messages. */ 88 { 0, 0xffffffffU, 0, "ipsecah_default_soft_bytes"}, 89 { 0, 0xffffffffU, 0, "ipsecah_default_hard_bytes"}, 90 { 0, 0xffffffffU, 24000, "ipsecah_default_soft_addtime"}, 91 { 0, 0xffffffffU, 28800, "ipsecah_default_hard_addtime"}, 92 { 0, 0xffffffffU, 0, "ipsecah_default_soft_usetime"}, 93 { 0, 0xffffffffU, 0, "ipsecah_default_hard_usetime"}, 94 { 0, 1, 0, "ipsecah_log_unknown_spi"}, 95 }; 96 #define ipsecah_debug ipsecah_param_arr[0].ipsecah_param_value 97 #define ipsecah_age_interval ipsecah_param_arr[1].ipsecah_param_value 98 #define ipsecah_age_int_max ipsecah_param_arr[1].ipsecah_param_max 99 #define ipsecah_reap_delay ipsecah_param_arr[2].ipsecah_param_value 100 #define ipsecah_replay_size ipsecah_param_arr[3].ipsecah_param_value 101 #define ipsecah_acquire_timeout ipsecah_param_arr[4].ipsecah_param_value 102 #define ipsecah_larval_timeout ipsecah_param_arr[5].ipsecah_param_value 103 #define ipsecah_default_soft_bytes ipsecah_param_arr[6].ipsecah_param_value 104 #define ipsecah_default_hard_bytes ipsecah_param_arr[7].ipsecah_param_value 105 #define ipsecah_default_soft_addtime ipsecah_param_arr[8].ipsecah_param_value 106 #define ipsecah_default_hard_addtime ipsecah_param_arr[9].ipsecah_param_value 107 #define ipsecah_default_soft_usetime ipsecah_param_arr[10].ipsecah_param_value 108 #define ipsecah_default_hard_usetime ipsecah_param_arr[11].ipsecah_param_value 109 #define ipsecah_log_unknown_spi ipsecah_param_arr[12].ipsecah_param_value 110 111 #define ah0dbg(a) printf a 112 /* NOTE: != 0 instead of > 0 so lint doesn't complain. */ 113 #define ah1dbg(a) if (ipsecah_debug != 0) printf a 114 #define ah2dbg(a) if (ipsecah_debug > 1) printf a 115 #define ah3dbg(a) if (ipsecah_debug > 2) printf a 116 117 static IDP ipsecah_g_nd; 118 119 /* 120 * XXX This is broken. Padding should be determined dynamically 121 * depending on the ICV size and IP version number so that the 122 * total AH header size is a multiple of 32 bits or 64 bits 123 * for V4 and V6 respectively. For 96bit ICVs we have no problems. 124 * Anything different from that, we need to fix our code. 125 */ 126 #define IPV4_PADDING_ALIGN 0x04 /* Multiple of 32 bits */ 127 #define IPV6_PADDING_ALIGN 0x04 /* Multiple of 32 bits */ 128 129 /* 130 * Helper macro. Avoids a call to msgdsize if there is only one 131 * mblk in the chain. 132 */ 133 #define AH_MSGSIZE(mp) ((mp)->b_cont != NULL ? msgdsize(mp) : MBLKL(mp)) 134 135 static ipsec_status_t ah_auth_out_done(mblk_t *); 136 static ipsec_status_t ah_auth_in_done(mblk_t *); 137 static mblk_t *ah_process_ip_options_v4(mblk_t *, ipsa_t *, int *, uint_t, 138 boolean_t); 139 static mblk_t *ah_process_ip_options_v6(mblk_t *, ipsa_t *, int *, uint_t, 140 boolean_t); 141 static void ah_getspi(mblk_t *, keysock_in_t *); 142 static ipsec_status_t ah_inbound_accelerated(mblk_t *, boolean_t, ipsa_t *, 143 uint32_t); 144 static ipsec_status_t ah_outbound_accelerated_v4(mblk_t *, ipsa_t *); 145 static ipsec_status_t ah_outbound_accelerated_v6(mblk_t *, ipsa_t *); 146 static ipsec_status_t ah_outbound(mblk_t *); 147 148 static int ipsecah_open(queue_t *, dev_t *, int, int, cred_t *); 149 static int ipsecah_close(queue_t *); 150 static void ipsecah_rput(queue_t *, mblk_t *); 151 static void ipsecah_wput(queue_t *, mblk_t *); 152 static void ah_send_acquire(ipsacq_t *, mblk_t *); 153 static boolean_t ah_register_out(uint32_t, uint32_t, uint_t); 154 155 static struct module_info info = { 156 5136, "ipsecah", 0, INFPSZ, 65536, 1024 157 }; 158 159 static struct qinit rinit = { 160 (pfi_t)ipsecah_rput, NULL, ipsecah_open, ipsecah_close, NULL, &info, 161 NULL 162 }; 163 164 static struct qinit winit = { 165 (pfi_t)ipsecah_wput, NULL, ipsecah_open, ipsecah_close, NULL, &info, 166 NULL 167 }; 168 169 struct streamtab ipsecahinfo = { 170 &rinit, &winit, NULL, NULL 171 }; 172 173 /* 174 * Keysock instance of AH. "There can be only one." :) 175 * Use casptr() on this because I don't set it until KEYSOCK_HELLO comes down. 176 * Paired up with the ah_pfkey_q is the ah_event, which will age SAs. 177 */ 178 static queue_t *ah_pfkey_q; 179 static timeout_id_t ah_event; 180 static taskq_t *ah_taskq; 181 182 static mblk_t *ah_ip_unbind; 183 184 /* 185 * Stats. This may eventually become a full-blown SNMP MIB once that spec 186 * stabilizes. 187 */ 188 typedef struct 189 { 190 kstat_named_t ah_stat_num_aalgs; 191 kstat_named_t ah_stat_good_auth; 192 kstat_named_t ah_stat_bad_auth; 193 kstat_named_t ah_stat_replay_failures; 194 kstat_named_t ah_stat_replay_early_failures; 195 kstat_named_t ah_stat_keysock_in; 196 kstat_named_t ah_stat_out_requests; 197 kstat_named_t ah_stat_acquire_requests; 198 kstat_named_t ah_stat_bytes_expired; 199 kstat_named_t ah_stat_out_discards; 200 kstat_named_t ah_stat_in_accelerated; 201 kstat_named_t ah_stat_out_accelerated; 202 kstat_named_t ah_stat_noaccel; 203 kstat_named_t ah_stat_crypto_sync; 204 kstat_named_t ah_stat_crypto_async; 205 kstat_named_t ah_stat_crypto_failures; 206 } ah_kstats_t; 207 208 #define AH_BUMP_STAT(x) (ah_kstats->ah_stat_ ## x).value.ui64++ 209 #define AH_DEBUMP_STAT(x) (ah_kstats->ah_stat_ ## x).value.ui64-- 210 211 uint32_t ah_hash_size = IPSEC_DEFAULT_HASH_SIZE; 212 static kstat_t *ah_ksp; 213 static ah_kstats_t *ah_kstats; 214 215 static int ah_kstat_update(kstat_t *, int); 216 217 uint64_t ipsacq_maxpackets = IPSACQ_MAXPACKETS; 218 219 static boolean_t 220 ah_kstat_init(void) 221 { 222 223 ah_ksp = kstat_create("ipsecah", 0, "ah_stat", "net", 224 KSTAT_TYPE_NAMED, sizeof (*ah_kstats) / sizeof (kstat_named_t), 225 KSTAT_FLAG_PERSISTENT); 226 227 if (ah_ksp == NULL) 228 return (B_FALSE); 229 230 ah_kstats = ah_ksp->ks_data; 231 232 ah_ksp->ks_update = ah_kstat_update; 233 234 #define K64 KSTAT_DATA_UINT64 235 #define KI(x) kstat_named_init(&(ah_kstats->ah_stat_##x), #x, K64) 236 237 KI(num_aalgs); 238 KI(good_auth); 239 KI(bad_auth); 240 KI(replay_failures); 241 KI(replay_early_failures); 242 KI(keysock_in); 243 KI(out_requests); 244 KI(acquire_requests); 245 KI(bytes_expired); 246 KI(out_discards); 247 KI(in_accelerated); 248 KI(out_accelerated); 249 KI(noaccel); 250 KI(crypto_sync); 251 KI(crypto_async); 252 KI(crypto_failures); 253 254 #undef KI 255 #undef K64 256 257 kstat_install(ah_ksp); 258 IP_ACQUIRE_STAT(maxpackets, ipsacq_maxpackets); 259 return (B_TRUE); 260 } 261 262 static int 263 ah_kstat_update(kstat_t *kp, int rw) 264 { 265 ah_kstats_t *ekp; 266 267 if ((kp == NULL) || (kp->ks_data == NULL)) 268 return (EIO); 269 270 if (rw == KSTAT_WRITE) 271 return (EACCES); 272 273 ASSERT(kp == ah_ksp); 274 ekp = (ah_kstats_t *)kp->ks_data; 275 ASSERT(ekp == ah_kstats); 276 277 mutex_enter(&alg_lock); 278 ekp->ah_stat_num_aalgs.value.ui64 = ipsec_nalgs[IPSEC_ALG_AUTH]; 279 mutex_exit(&alg_lock); 280 281 return (0); 282 } 283 284 /* 285 * Don't have to lock ipsec_age_interval, as only one thread will access it at 286 * a time, because I control the one function that does a qtimeout() on 287 * ah_pfkey_q. 288 */ 289 /* ARGSUSED */ 290 static void 291 ah_ager(void *ignoreme) 292 { 293 hrtime_t begin = gethrtime(); 294 295 sadb_ager(&ah_sadb.s_v4, ah_pfkey_q, ah_sadb.s_ip_q, 296 ipsecah_reap_delay); 297 sadb_ager(&ah_sadb.s_v6, ah_pfkey_q, ah_sadb.s_ip_q, 298 ipsecah_reap_delay); 299 300 ah_event = sadb_retimeout(begin, ah_pfkey_q, ah_ager, 301 &ipsecah_age_interval, ipsecah_age_int_max, info.mi_idnum); 302 } 303 304 /* 305 * Get an AH NDD parameter. 306 */ 307 /* ARGSUSED */ 308 static int 309 ipsecah_param_get(q, mp, cp, cr) 310 queue_t *q; 311 mblk_t *mp; 312 caddr_t cp; 313 cred_t *cr; 314 { 315 ipsecahparam_t *ipsecahpa = (ipsecahparam_t *)cp; 316 uint_t value; 317 318 mutex_enter(&ipsecah_param_lock); 319 value = ipsecahpa->ipsecah_param_value; 320 mutex_exit(&ipsecah_param_lock); 321 322 (void) mi_mpprintf(mp, "%u", value); 323 return (0); 324 } 325 326 /* 327 * This routine sets an NDD variable in a ipsecahparam_t structure. 328 */ 329 /* ARGSUSED */ 330 static int 331 ipsecah_param_set(q, mp, value, cp, cr) 332 queue_t *q; 333 mblk_t *mp; 334 char *value; 335 caddr_t cp; 336 cred_t *cr; 337 { 338 ulong_t new_value; 339 ipsecahparam_t *ipsecahpa = (ipsecahparam_t *)cp; 340 341 /* 342 * Fail the request if the new value does not lie within the 343 * required bounds. 344 */ 345 if (ddi_strtoul(value, NULL, 10, &new_value) != 0 || 346 new_value < ipsecahpa->ipsecah_param_min || 347 new_value > ipsecahpa->ipsecah_param_max) { 348 return (EINVAL); 349 } 350 351 /* Set the new value */ 352 mutex_enter(&ipsecah_param_lock); 353 ipsecahpa->ipsecah_param_value = new_value; 354 mutex_exit(&ipsecah_param_lock); 355 return (0); 356 } 357 358 /* 359 * Using lifetime NDD variables, fill in an extended combination's 360 * lifetime information. 361 */ 362 void 363 ipsecah_fill_defs(sadb_x_ecomb_t *ecomb) 364 { 365 ecomb->sadb_x_ecomb_soft_bytes = ipsecah_default_soft_bytes; 366 ecomb->sadb_x_ecomb_hard_bytes = ipsecah_default_hard_bytes; 367 ecomb->sadb_x_ecomb_soft_addtime = ipsecah_default_soft_addtime; 368 ecomb->sadb_x_ecomb_hard_addtime = ipsecah_default_hard_addtime; 369 ecomb->sadb_x_ecomb_soft_usetime = ipsecah_default_soft_usetime; 370 ecomb->sadb_x_ecomb_hard_usetime = ipsecah_default_hard_usetime; 371 } 372 373 /* 374 * Initialize things for AH at module load time. 375 */ 376 boolean_t 377 ipsecah_ddi_init(void) 378 { 379 int count; 380 ipsecahparam_t *ahp = ipsecah_param_arr; 381 382 for (count = A_CNT(ipsecah_param_arr); count-- > 0; ahp++) { 383 if (ahp->ipsecah_param_name != NULL && 384 ahp->ipsecah_param_name[0]) { 385 if (!nd_load(&ipsecah_g_nd, ahp->ipsecah_param_name, 386 ipsecah_param_get, ipsecah_param_set, 387 (caddr_t)ahp)) { 388 nd_free(&ipsecah_g_nd); 389 return (B_FALSE); 390 } 391 } 392 } 393 394 if (!ah_kstat_init()) { 395 nd_free(&ipsecah_g_nd); 396 return (B_FALSE); 397 } 398 399 ah_taskq = taskq_create("ah_taskq", 1, minclsyspri, 400 IPSEC_TASKQ_MIN, IPSEC_TASKQ_MAX, 0); 401 402 ah_sadb.s_acquire_timeout = &ipsecah_acquire_timeout; 403 ah_sadb.s_acqfn = ah_send_acquire; 404 405 sadbp_init("AH", &ah_sadb, SADB_SATYPE_AH, ah_hash_size); 406 407 mutex_init(&ipsecah_param_lock, NULL, MUTEX_DEFAULT, 0); 408 409 ip_drop_register(&ah_dropper, "IPsec AH"); 410 411 return (B_TRUE); 412 } 413 414 /* 415 * Destroy things for AH at module unload time. 416 */ 417 void 418 ipsecah_ddi_destroy(void) 419 { 420 ah1dbg(("In ddi_destroy.\n")); 421 422 sadbp_destroy(&ah_sadb); 423 ip_drop_unregister(&ah_dropper); 424 taskq_destroy(ah_taskq); 425 mutex_destroy(&ipsecah_param_lock); 426 nd_free(&ipsecah_g_nd); 427 428 kstat_delete(ah_ksp); 429 } 430 431 /* 432 * AH module open routine. The module should be opened by keysock. 433 */ 434 /* ARGSUSED */ 435 static int 436 ipsecah_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 437 { 438 if (secpolicy_net_config(credp, B_FALSE) != 0) { 439 ah1dbg(("Non-privileged user trying to open ipsecah.\n")); 440 return (EPERM); 441 } 442 443 if (q->q_ptr != NULL) 444 return (0); /* Re-open of an already open instance. */ 445 446 if (sflag != MODOPEN) 447 return (EINVAL); 448 449 /* 450 * ASSUMPTIONS (because I'm MT_OCEXCL): 451 * 452 * * I'm being pushed on top of IP for all my opens (incl. #1). 453 * * Only ipsecah_open() can write into ah_sadb.s_ip_q. 454 * * Because of this, I can check lazily for ah_sadb.s_ip_q. 455 * 456 * If these assumptions are wrong, I'm in BIG trouble... 457 */ 458 459 q->q_ptr = q; /* just so I know I'm open */ 460 461 if (ah_sadb.s_ip_q == NULL) { 462 struct T_unbind_req *tur; 463 464 ah_sadb.s_ip_q = WR(q); 465 /* Allocate an unbind... */ 466 ah_ip_unbind = allocb(sizeof (struct T_unbind_req), BPRI_HI); 467 468 /* 469 * Send down T_BIND_REQ to bind IPPROTO_AH. 470 * Handle the ACK here in AH. 471 */ 472 qprocson(q); 473 if (ah_ip_unbind == NULL || 474 !sadb_t_bind_req(ah_sadb.s_ip_q, IPPROTO_AH)) { 475 if (ah_ip_unbind != NULL) { 476 freeb(ah_ip_unbind); 477 ah_ip_unbind = NULL; 478 } 479 q->q_ptr = NULL; 480 qprocsoff(q); 481 return (ENOMEM); 482 } 483 484 ah_ip_unbind->b_datap->db_type = M_PROTO; 485 tur = (struct T_unbind_req *)ah_ip_unbind->b_rptr; 486 tur->PRIM_type = T_UNBIND_REQ; 487 } else { 488 qprocson(q); 489 } 490 491 /* 492 * For now, there's not much I can do. I'll be getting a message 493 * passed down to me from keysock (in my wput), and a T_BIND_ACK 494 * up from IP (in my rput). 495 */ 496 497 return (0); 498 } 499 500 /* 501 * AH module close routine. 502 */ 503 static int 504 ipsecah_close(queue_t *q) 505 { 506 /* 507 * If ah_sadb.s_ip_q is attached to this instance, send a 508 * T_UNBIND_REQ to IP for the instance before doing 509 * a qprocsoff(). 510 */ 511 if (WR(q) == ah_sadb.s_ip_q && ah_ip_unbind != NULL) { 512 putnext(WR(q), ah_ip_unbind); 513 ah_ip_unbind = NULL; 514 } 515 516 /* 517 * Clean up q_ptr, if needed. 518 */ 519 qprocsoff(q); 520 521 /* Keysock queue check is safe, because of OCEXCL perimeter. */ 522 523 if (q == ah_pfkey_q) { 524 ah0dbg(("ipsecah_close: Ummm... keysock is closing AH.\n")); 525 ah_pfkey_q = NULL; 526 /* Detach qtimeouts. */ 527 (void) quntimeout(q, ah_event); 528 } 529 530 if (WR(q) == ah_sadb.s_ip_q) { 531 /* 532 * If the ah_sadb.s_ip_q is attached to this instance, find 533 * another. The OCEXCL outer perimeter helps us here. 534 */ 535 536 ah_sadb.s_ip_q = NULL; 537 538 /* 539 * Find a replacement queue for ah_sadb.s_ip_q. 540 */ 541 if (ah_pfkey_q != NULL && ah_pfkey_q != RD(q)) { 542 /* 543 * See if we can use the pfkey_q. 544 */ 545 ah_sadb.s_ip_q = WR(ah_pfkey_q); 546 } 547 548 if (ah_sadb.s_ip_q == NULL || 549 !sadb_t_bind_req(ah_sadb.s_ip_q, IPPROTO_AH)) { 550 ah1dbg(("ipsecah: Can't reassign ah_sadb.s_ip_q.\n")); 551 ah_sadb.s_ip_q = NULL; 552 } else { 553 ah_ip_unbind = allocb(sizeof (struct T_unbind_req), 554 BPRI_HI); 555 556 if (ah_ip_unbind != NULL) { 557 struct T_unbind_req *tur; 558 559 ah_ip_unbind->b_datap->db_type = M_PROTO; 560 tur = (struct T_unbind_req *) 561 ah_ip_unbind->b_rptr; 562 tur->PRIM_type = T_UNBIND_REQ; 563 } 564 /* If it's NULL, I can't do much here. */ 565 } 566 } 567 568 return (0); 569 } 570 571 /* 572 * AH module read put routine. 573 */ 574 /* ARGSUSED */ 575 static void 576 ipsecah_rput(queue_t *q, mblk_t *mp) 577 { 578 keysock_in_t *ksi; 579 int *addrtype; 580 ire_t *ire; 581 mblk_t *ire_mp, *last_mp; 582 583 switch (mp->b_datap->db_type) { 584 case M_CTL: 585 /* 586 * IPsec request of some variety from IP. IPSEC_{IN,OUT} 587 * are the common cases, but even ICMP error messages from IP 588 * may rise up here. 589 * 590 * Ummmm, actually, this can also be the reflected KEYSOCK_IN 591 * message, with an IRE_DB_TYPE hung off at the end. 592 */ 593 switch (((ipsec_info_t *)(mp->b_rptr))->ipsec_info_type) { 594 case KEYSOCK_IN: 595 last_mp = mp; 596 while (last_mp->b_cont != NULL && 597 last_mp->b_cont->b_datap->db_type != IRE_DB_TYPE) 598 last_mp = last_mp->b_cont; 599 600 if (last_mp->b_cont == NULL) { 601 freemsg(mp); 602 break; /* Out of switch. */ 603 } 604 605 ire_mp = last_mp->b_cont; 606 last_mp->b_cont = NULL; 607 608 ksi = (keysock_in_t *)mp->b_rptr; 609 610 if (ksi->ks_in_srctype == KS_IN_ADDR_UNKNOWN) 611 addrtype = &ksi->ks_in_srctype; 612 else if (ksi->ks_in_dsttype == KS_IN_ADDR_UNKNOWN) 613 addrtype = &ksi->ks_in_dsttype; 614 else if (ksi->ks_in_proxytype == KS_IN_ADDR_UNKNOWN) 615 addrtype = &ksi->ks_in_proxytype; 616 617 ire = (ire_t *)ire_mp->b_rptr; 618 619 *addrtype = sadb_addrset(ire); 620 621 freemsg(ire_mp); 622 if (ah_pfkey_q != NULL) { 623 /* 624 * Decrement counter to make up for 625 * auto-increment in ipsecah_wput(). 626 * I'm running all MT-hot through here, so 627 * don't worry about perimeters and lateral 628 * puts. 629 */ 630 AH_DEBUMP_STAT(keysock_in); 631 ipsecah_wput(WR(ah_pfkey_q), mp); 632 } else { 633 freemsg(mp); 634 } 635 break; 636 default: 637 freemsg(mp); 638 break; 639 } 640 break; 641 case M_PROTO: 642 case M_PCPROTO: 643 /* TPI message of some sort. */ 644 switch (*((t_scalar_t *)mp->b_rptr)) { 645 case T_BIND_ACK: 646 /* We expect this. */ 647 ah3dbg(("Thank you IP from AH for T_BIND_ACK\n")); 648 break; 649 case T_ERROR_ACK: 650 cmn_err(CE_WARN, 651 "ipsecah: AH received T_ERROR_ACK from IP."); 652 break; 653 case T_OK_ACK: 654 /* Probably from a (rarely sent) T_UNBIND_REQ. */ 655 break; 656 default: 657 ah1dbg(("Unknown M_{,PC}PROTO message.\n")); 658 } 659 freemsg(mp); 660 break; 661 default: 662 /* For now, passthru message. */ 663 ah2dbg(("AH got unknown mblk type %d.\n", 664 mp->b_datap->db_type)); 665 putnext(q, mp); 666 } 667 } 668 669 /* 670 * Construct an SADB_REGISTER message with the current algorithms. 671 */ 672 static boolean_t 673 ah_register_out(uint32_t sequence, uint32_t pid, uint_t serial) 674 { 675 mblk_t *mp; 676 boolean_t rc = B_TRUE; 677 sadb_msg_t *samsg; 678 sadb_supported_t *sasupp; 679 sadb_alg_t *saalg; 680 uint_t allocsize = sizeof (*samsg); 681 uint_t i, numalgs_snap; 682 ipsec_alginfo_t **authalgs; 683 uint_t num_aalgs; 684 685 /* Allocate the KEYSOCK_OUT. */ 686 mp = sadb_keysock_out(serial); 687 if (mp == NULL) { 688 ah0dbg(("ah_register_out: couldn't allocate mblk.\n")); 689 return (B_FALSE); 690 } 691 692 /* 693 * Allocate the PF_KEY message that follows KEYSOCK_OUT. 694 * The alg reader lock needs to be held while allocating 695 * the variable part (i.e. the algorithms) of the message. 696 */ 697 698 mutex_enter(&alg_lock); 699 700 /* 701 * Return only valid algorithms, so the number of algorithms 702 * to send up may be less than the number of algorithm entries 703 * in the table. 704 */ 705 authalgs = ipsec_alglists[IPSEC_ALG_AUTH]; 706 for (num_aalgs = 0, i = 0; i < IPSEC_MAX_ALGS; i++) 707 if (authalgs[i] != NULL && ALG_VALID(authalgs[i])) 708 num_aalgs++; 709 710 /* 711 * Fill SADB_REGISTER message's algorithm descriptors. Hold 712 * down the lock while filling it. 713 */ 714 if (num_aalgs != 0) { 715 allocsize += (num_aalgs * sizeof (*saalg)); 716 allocsize += sizeof (*sasupp); 717 } 718 mp->b_cont = allocb(allocsize, BPRI_HI); 719 if (mp->b_cont == NULL) { 720 mutex_exit(&alg_lock); 721 freemsg(mp); 722 return (B_FALSE); 723 } 724 725 mp->b_cont->b_wptr += allocsize; 726 if (num_aalgs != 0) { 727 728 saalg = (sadb_alg_t *)(mp->b_cont->b_rptr + sizeof (*samsg) + 729 sizeof (*sasupp)); 730 ASSERT(((ulong_t)saalg & 0x7) == 0); 731 732 numalgs_snap = 0; 733 for (i = 0; 734 ((i < IPSEC_MAX_ALGS) && (numalgs_snap < num_aalgs)); i++) { 735 if (authalgs[i] == NULL || !ALG_VALID(authalgs[i])) 736 continue; 737 738 saalg->sadb_alg_id = authalgs[i]->alg_id; 739 saalg->sadb_alg_ivlen = 0; 740 saalg->sadb_alg_minbits = authalgs[i]->alg_ef_minbits; 741 saalg->sadb_alg_maxbits = authalgs[i]->alg_ef_maxbits; 742 saalg->sadb_x_alg_increment = 743 authalgs[i]->alg_increment; 744 saalg->sadb_x_alg_defincr = authalgs[i]->alg_ef_default; 745 numalgs_snap++; 746 saalg++; 747 } 748 ASSERT(numalgs_snap == num_aalgs); 749 #ifdef DEBUG 750 /* 751 * Reality check to make sure I snagged all of the 752 * algorithms. 753 */ 754 for (; i < IPSEC_MAX_ALGS; i++) 755 if (authalgs[i] != NULL && ALG_VALID(authalgs[i])) 756 cmn_err(CE_PANIC, 757 "ah_register_out()! Missed #%d.\n", i); 758 #endif /* DEBUG */ 759 } 760 761 mutex_exit(&alg_lock); 762 763 /* Now fill the restof the SADB_REGISTER message. */ 764 765 samsg = (sadb_msg_t *)mp->b_cont->b_rptr; 766 samsg->sadb_msg_version = PF_KEY_V2; 767 samsg->sadb_msg_type = SADB_REGISTER; 768 samsg->sadb_msg_errno = 0; 769 samsg->sadb_msg_satype = SADB_SATYPE_AH; 770 samsg->sadb_msg_len = SADB_8TO64(allocsize); 771 samsg->sadb_msg_reserved = 0; 772 /* 773 * Assume caller has sufficient sequence/pid number info. If it's one 774 * from me over a new alg., I could give two hoots about sequence. 775 */ 776 samsg->sadb_msg_seq = sequence; 777 samsg->sadb_msg_pid = pid; 778 779 if (allocsize > sizeof (*samsg)) { 780 sasupp = (sadb_supported_t *)(samsg + 1); 781 sasupp->sadb_supported_len = 782 SADB_8TO64(allocsize - sizeof (sadb_msg_t)); 783 sasupp->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; 784 sasupp->sadb_supported_reserved = 0; 785 } 786 787 if (ah_pfkey_q != NULL) 788 putnext(ah_pfkey_q, mp); 789 else { 790 rc = B_FALSE; 791 freemsg(mp); 792 } 793 794 return (rc); 795 } 796 797 /* 798 * Invoked when the algorithm table changes. Causes SADB_REGISTER 799 * messages continaining the current list of algorithms to be 800 * sent up to the AH listeners. 801 */ 802 void 803 ipsecah_algs_changed(void) 804 { 805 /* 806 * Time to send a PF_KEY SADB_REGISTER message to AH listeners 807 * everywhere. (The function itself checks for NULL ah_pfkey_q.) 808 */ 809 (void) ah_register_out(0, 0, 0); 810 } 811 812 /* 813 * Stub function that taskq_dispatch() invokes to take the mblk (in arg) 814 * and put() it into AH and STREAMS again. 815 */ 816 static void 817 inbound_task(void *arg) 818 { 819 ah_t *ah; 820 mblk_t *mp = (mblk_t *)arg; 821 ipsec_in_t *ii = (ipsec_in_t *)mp->b_rptr; 822 int ipsec_rc; 823 824 ah2dbg(("in AH inbound_task")); 825 826 ah = ipsec_inbound_ah_sa(mp); 827 if (ah == NULL) 828 return; 829 ASSERT(ii->ipsec_in_ah_sa != NULL); 830 ipsec_rc = ii->ipsec_in_ah_sa->ipsa_input_func(mp, ah); 831 if (ipsec_rc != IPSEC_STATUS_SUCCESS) 832 return; 833 ip_fanout_proto_again(mp, NULL, NULL, NULL); 834 } 835 836 837 /* 838 * Now that weak-key passed, actually ADD the security association, and 839 * send back a reply ADD message. 840 */ 841 static int 842 ah_add_sa_finish(mblk_t *mp, sadb_msg_t *samsg, keysock_in_t *ksi) 843 { 844 isaf_t *primary, *secondary, *inbound, *outbound; 845 sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 846 sadb_address_t *dstext = 847 (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 848 struct sockaddr_in *dst; 849 struct sockaddr_in6 *dst6; 850 boolean_t is_ipv4, clone = B_FALSE, is_inbound = B_FALSE; 851 uint32_t *dstaddr; 852 ipsa_t *larval; 853 ipsacq_t *acqrec; 854 iacqf_t *acq_bucket; 855 mblk_t *acq_msgs = NULL; 856 mblk_t *lpkt; 857 int rc; 858 sadb_t *sp; 859 int outhash; 860 861 /* 862 * Locate the appropriate table(s). 863 */ 864 865 dst = (struct sockaddr_in *)(dstext + 1); 866 dst6 = (struct sockaddr_in6 *)dst; 867 is_ipv4 = (dst->sin_family == AF_INET); 868 if (is_ipv4) { 869 sp = &ah_sadb.s_v4; 870 dstaddr = (uint32_t *)(&dst->sin_addr); 871 outhash = OUTBOUND_HASH_V4(sp, *(ipaddr_t *)dstaddr); 872 } else { 873 ASSERT(dst->sin_family == AF_INET6); 874 sp = &ah_sadb.s_v6; 875 dstaddr = (uint32_t *)(&dst6->sin6_addr); 876 outhash = OUTBOUND_HASH_V6(sp, *(in6_addr_t *)dstaddr); 877 } 878 879 inbound = INBOUND_BUCKET(sp, assoc->sadb_sa_spi); 880 outbound = &sp->sdb_of[outhash]; 881 882 switch (ksi->ks_in_dsttype) { 883 case KS_IN_ADDR_MBCAST: 884 clone = B_TRUE; /* All mcast SAs can be bidirectional */ 885 /* FALLTHRU */ 886 case KS_IN_ADDR_ME: 887 primary = inbound; 888 secondary = outbound; 889 /* 890 * If the source address is either one of mine, or unspecified 891 * (which is best summed up by saying "not 'not mine'"), 892 * then the association is potentially bi-directional, 893 * in that it can be used for inbound traffic and outbound 894 * traffic. The best example of such and SA is a multicast 895 * SA (which allows me to receive the outbound traffic). 896 */ 897 if (ksi->ks_in_srctype != KS_IN_ADDR_NOTME) 898 clone = B_TRUE; 899 is_inbound = B_TRUE; 900 break; 901 case KS_IN_ADDR_NOTME: 902 primary = outbound; 903 secondary = inbound; 904 /* 905 * If the source address literally not mine (either 906 * unspecified or not mine), then this SA may have an 907 * address that WILL be mine after some configuration. 908 * We pay the price for this by making it a bi-directional 909 * SA. 910 */ 911 if (ksi->ks_in_srctype != KS_IN_ADDR_ME) 912 clone = B_TRUE; 913 break; 914 default: 915 samsg->sadb_x_msg_diagnostic = SADB_X_DIAGNOSTIC_BAD_DST; 916 return (EINVAL); 917 } 918 919 /* 920 * Find a ACQUIRE list entry if possible. If we've added an SA that 921 * suits the needs of an ACQUIRE list entry, we can eliminate the 922 * ACQUIRE list entry and transmit the enqueued packets. Use the 923 * high-bit of the sequence number to queue it. Key off destination 924 * addr, and change acqrec's state. 925 */ 926 927 if (samsg->sadb_msg_seq & IACQF_LOWEST_SEQ) { 928 acq_bucket = &sp->sdb_acq[outhash]; 929 mutex_enter(&acq_bucket->iacqf_lock); 930 for (acqrec = acq_bucket->iacqf_ipsacq; acqrec != NULL; 931 acqrec = acqrec->ipsacq_next) { 932 mutex_enter(&acqrec->ipsacq_lock); 933 /* 934 * Q: I only check sequence. Should I check dst? 935 * A: Yes, check dest because those are the packets 936 * that are queued up. 937 */ 938 if (acqrec->ipsacq_seq == samsg->sadb_msg_seq && 939 IPSA_ARE_ADDR_EQUAL(dstaddr, 940 acqrec->ipsacq_dstaddr, acqrec->ipsacq_addrfam)) 941 break; 942 mutex_exit(&acqrec->ipsacq_lock); 943 } 944 if (acqrec != NULL) { 945 /* 946 * AHA! I found an ACQUIRE record for this SA. 947 * Grab the msg list, and free the acquire record. 948 * I already am holding the lock for this record, 949 * so all I have to do is free it. 950 */ 951 acq_msgs = acqrec->ipsacq_mp; 952 acqrec->ipsacq_mp = NULL; 953 mutex_exit(&acqrec->ipsacq_lock); 954 sadb_destroy_acquire(acqrec); 955 } 956 mutex_exit(&acq_bucket->iacqf_lock); 957 } 958 959 /* 960 * Find PF_KEY message, and see if I'm an update. If so, find entry 961 * in larval list (if there). 962 */ 963 964 larval = NULL; 965 966 if (samsg->sadb_msg_type == SADB_UPDATE) { 967 mutex_enter(&inbound->isaf_lock); 968 larval = ipsec_getassocbyspi(inbound, assoc->sadb_sa_spi, 969 ALL_ZEROES_PTR, dstaddr, dst->sin_family); 970 mutex_exit(&inbound->isaf_lock); 971 972 if ((larval == NULL) || 973 (larval->ipsa_state != IPSA_STATE_LARVAL)) { 974 ah0dbg(("Larval update, but larval disappeared.\n")); 975 return (ESRCH); 976 } /* Else sadb_common_add unlinks it for me! */ 977 } 978 979 lpkt = NULL; 980 if (larval != NULL) 981 lpkt = sadb_clear_lpkt(larval); 982 983 rc = sadb_common_add(ah_sadb.s_ip_q, ah_pfkey_q, mp, samsg, ksi, 984 primary, secondary, larval, clone, is_inbound); 985 986 /* 987 * How much more stack will I create with all of these 988 * ah_inbound_* and ah_outbound_*() calls? 989 */ 990 991 992 if (rc == 0 && lpkt != NULL) 993 rc = !taskq_dispatch(ah_taskq, inbound_task, 994 (void *) lpkt, TQ_NOSLEEP); 995 996 if (rc != 0) { 997 ip_drop_packet(lpkt, B_TRUE, NULL, NULL, 998 &ipdrops_sadb_inlarval_timeout, &ah_dropper); 999 } 1000 1001 while (acq_msgs != NULL) { 1002 mblk_t *mp = acq_msgs; 1003 1004 acq_msgs = acq_msgs->b_next; 1005 mp->b_next = NULL; 1006 if (rc == 0) { 1007 ipsec_out_t *io = (ipsec_out_t *)mp->b_rptr; 1008 1009 ASSERT(ah_sadb.s_ip_q != NULL); 1010 if (ipsec_outbound_sa(mp, IPPROTO_AH)) { 1011 io->ipsec_out_ah_done = B_TRUE; 1012 if (ah_outbound(mp) == IPSEC_STATUS_SUCCESS) { 1013 ipha_t *ipha = (ipha_t *) 1014 mp->b_cont->b_rptr; 1015 if (is_ipv4) { 1016 ip_wput_ipsec_out(NULL, mp, 1017 ipha, NULL, NULL); 1018 } else { 1019 ip6_t *ip6h = (ip6_t *)ipha; 1020 ip_wput_ipsec_out_v6(NULL, 1021 mp, ip6h, NULL, NULL); 1022 } 1023 } 1024 continue; 1025 } 1026 } 1027 AH_BUMP_STAT(out_discards); 1028 ip_drop_packet(mp, B_FALSE, NULL, NULL, 1029 &ipdrops_sadb_acquire_timeout, &ah_dropper); 1030 } 1031 1032 return (rc); 1033 } 1034 1035 /* 1036 * Add new AH security association. This may become a generic AH/ESP 1037 * routine eventually. 1038 */ 1039 static int 1040 ah_add_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic) 1041 { 1042 sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 1043 sadb_address_t *srcext = 1044 (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC]; 1045 sadb_address_t *dstext = 1046 (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 1047 sadb_key_t *key = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH]; 1048 struct sockaddr_in *src, *dst; 1049 /* We don't need sockaddr_in6 for now. */ 1050 sadb_lifetime_t *soft = 1051 (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_SOFT]; 1052 sadb_lifetime_t *hard = 1053 (sadb_lifetime_t *)ksi->ks_in_extv[SADB_EXT_LIFETIME_HARD]; 1054 ipsec_alginfo_t *aalg; 1055 1056 /* I need certain extensions present for an ADD message. */ 1057 if (srcext == NULL) { 1058 *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC; 1059 return (EINVAL); 1060 } 1061 if (dstext == NULL) { 1062 *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST; 1063 return (EINVAL); 1064 } 1065 if (assoc == NULL) { 1066 *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA; 1067 return (EINVAL); 1068 } 1069 if (key == NULL) { 1070 *diagnostic = SADB_X_DIAGNOSTIC_MISSING_AKEY; 1071 return (EINVAL); 1072 } 1073 1074 src = (struct sockaddr_in *)(srcext + 1); 1075 dst = (struct sockaddr_in *)(dstext + 1); 1076 1077 /* Sundry ADD-specific reality checks. */ 1078 /* XXX STATS : Logging/stats here? */ 1079 1080 if (assoc->sadb_sa_state != SADB_SASTATE_MATURE) { 1081 *diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE; 1082 return (EINVAL); 1083 } 1084 if (assoc->sadb_sa_encrypt != SADB_EALG_NONE) { 1085 *diagnostic = SADB_X_DIAGNOSTIC_ENCR_NOTSUPP; 1086 return (EINVAL); 1087 } 1088 if (assoc->sadb_sa_flags & ~(SADB_SAFLAGS_NOREPLAY)) { 1089 *diagnostic = SADB_X_DIAGNOSTIC_BAD_SAFLAGS; 1090 return (EINVAL); 1091 } 1092 1093 if ((*diagnostic = sadb_hardsoftchk(hard, soft)) != 0) 1094 return (EINVAL); 1095 1096 if (src->sin_family != dst->sin_family) { 1097 *diagnostic = SADB_X_DIAGNOSTIC_AF_MISMATCH; 1098 return (EINVAL); 1099 } 1100 1101 /* Stuff I don't support, for now. XXX Diagnostic? */ 1102 if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL || 1103 ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL) 1104 return (EOPNOTSUPP); 1105 1106 /* 1107 * XXX Policy : I'm not checking identities or sensitivity 1108 * labels at this time, but if I did, I'd do them here, before I sent 1109 * the weak key check up to the algorithm. 1110 */ 1111 1112 /* verify that there is a mapping for the specified algorithm */ 1113 mutex_enter(&alg_lock); 1114 aalg = ipsec_alglists[IPSEC_ALG_AUTH][assoc->sadb_sa_auth]; 1115 if (aalg == NULL || !ALG_VALID(aalg)) { 1116 mutex_exit(&alg_lock); 1117 ah1dbg(("Couldn't find auth alg #%d.\n", assoc->sadb_sa_auth)); 1118 *diagnostic = SADB_X_DIAGNOSTIC_BAD_AALG; 1119 return (EINVAL); 1120 } 1121 ASSERT(aalg->alg_mech_type != CRYPTO_MECHANISM_INVALID); 1122 1123 /* sanity check key sizes */ 1124 if (!ipsec_valid_key_size(key->sadb_key_bits, aalg)) { 1125 mutex_exit(&alg_lock); 1126 *diagnostic = SADB_X_DIAGNOSTIC_BAD_AKEYBITS; 1127 return (EINVAL); 1128 } 1129 1130 /* check key and fix parity if needed */ 1131 if (ipsec_check_key(aalg->alg_mech_type, key, B_TRUE, 1132 diagnostic) != 0) { 1133 mutex_exit(&alg_lock); 1134 return (EINVAL); 1135 } 1136 1137 mutex_exit(&alg_lock); 1138 1139 return (ah_add_sa_finish(mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi)); 1140 } 1141 1142 /* 1143 * Update a security association. Updates come in two varieties. The first 1144 * is an update of lifetimes on a non-larval SA. The second is an update of 1145 * a larval SA, which ends up looking a lot more like an add. 1146 */ 1147 static int 1148 ah_update_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic) 1149 { 1150 sadb_address_t *dstext = 1151 (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 1152 struct sockaddr_in *sin; 1153 1154 if (dstext == NULL) { 1155 *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST; 1156 return (EINVAL); 1157 } 1158 sin = (struct sockaddr_in *)(dstext + 1); 1159 return (sadb_update_sa(mp, ksi, 1160 (sin->sin_family == AF_INET6) ? &ah_sadb.s_v6 : &ah_sadb.s_v4, 1161 diagnostic, ah_pfkey_q, ah_add_sa)); 1162 } 1163 1164 /* 1165 * Delete a security association. This is REALLY likely to be code common to 1166 * both AH and ESP. Find the association, then unlink it. 1167 */ 1168 static int 1169 ah_del_sa(mblk_t *mp, keysock_in_t *ksi, int *diagnostic) 1170 { 1171 sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA]; 1172 sadb_address_t *dstext = 1173 (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST]; 1174 sadb_address_t *srcext = 1175 (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC]; 1176 struct sockaddr_in *sin; 1177 1178 if (assoc == NULL) { 1179 if (dstext != NULL) 1180 sin = (struct sockaddr_in *)(dstext + 1); 1181 else if (srcext != NULL) 1182 sin = (struct sockaddr_in *)(srcext + 1); 1183 else { 1184 *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA; 1185 return (EINVAL); 1186 } 1187 return sadb_purge_sa(mp, ksi, 1188 (sin->sin_family == AF_INET6) ? &ah_sadb.s_v6 : 1189 &ah_sadb.s_v4, 1190 diagnostic, ah_pfkey_q, ah_sadb.s_ip_q); 1191 } 1192 1193 return (sadb_del_sa(mp, ksi, &ah_sadb, diagnostic, ah_pfkey_q)); 1194 } 1195 1196 /* 1197 * Convert the entire contents of all of AH's SA tables into PF_KEY SADB_DUMP 1198 * messages. 1199 */ 1200 static void 1201 ah_dump(mblk_t *mp, keysock_in_t *ksi) 1202 { 1203 int error; 1204 sadb_msg_t *samsg; 1205 1206 /* 1207 * Dump each fanout, bailing if error is non-zero. 1208 */ 1209 1210 error = sadb_dump(ah_pfkey_q, mp, ksi->ks_in_serial, &ah_sadb.s_v4); 1211 if (error != 0) 1212 goto bail; 1213 1214 error = sadb_dump(ah_pfkey_q, mp, ksi->ks_in_serial, &ah_sadb.s_v6); 1215 bail: 1216 ASSERT(mp->b_cont != NULL); 1217 samsg = (sadb_msg_t *)mp->b_cont->b_rptr; 1218 samsg->sadb_msg_errno = (uint8_t)error; 1219 sadb_pfkey_echo(ah_pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr, ksi, 1220 NULL); 1221 } 1222 1223 /* 1224 * AH parsing of PF_KEY messages. Keysock did most of the really silly 1225 * error cases. What I receive is a fully-formed, syntactically legal 1226 * PF_KEY message. I then need to check semantics... 1227 * 1228 * This code may become common to AH and ESP. Stay tuned. 1229 * 1230 * I also make the assumption that db_ref's are cool. If this assumption 1231 * is wrong, this means that someone other than keysock or me has been 1232 * mucking with PF_KEY messages. 1233 */ 1234 static void 1235 ah_parse_pfkey(mblk_t *mp) 1236 { 1237 mblk_t *msg = mp->b_cont; 1238 sadb_msg_t *samsg; 1239 keysock_in_t *ksi; 1240 int error; 1241 int diagnostic = SADB_X_DIAGNOSTIC_NONE; 1242 1243 ASSERT(msg != NULL); 1244 samsg = (sadb_msg_t *)msg->b_rptr; 1245 ksi = (keysock_in_t *)mp->b_rptr; 1246 1247 /* 1248 * If applicable, convert unspecified AF_INET6 to unspecified 1249 * AF_INET. 1250 */ 1251 sadb_srcaddrfix(ksi); 1252 1253 switch (samsg->sadb_msg_type) { 1254 case SADB_ADD: 1255 error = ah_add_sa(mp, ksi, &diagnostic); 1256 if (error != 0) { 1257 sadb_pfkey_error(ah_pfkey_q, mp, error, diagnostic, 1258 ksi->ks_in_serial); 1259 } 1260 /* else ah_add_sa() took care of things. */ 1261 break; 1262 case SADB_DELETE: 1263 error = ah_del_sa(mp, ksi, &diagnostic); 1264 if (error != 0) { 1265 sadb_pfkey_error(ah_pfkey_q, mp, error, diagnostic, 1266 ksi->ks_in_serial); 1267 } 1268 /* Else ah_del_sa() took care of things. */ 1269 break; 1270 case SADB_GET: 1271 error = sadb_get_sa(mp, ksi, &ah_sadb, &diagnostic, ah_pfkey_q); 1272 if (error != 0) { 1273 sadb_pfkey_error(ah_pfkey_q, mp, error, diagnostic, 1274 ksi->ks_in_serial); 1275 } 1276 /* Else sadb_get_sa() took care of things. */ 1277 break; 1278 case SADB_FLUSH: 1279 sadbp_flush(&ah_sadb); 1280 sadb_pfkey_echo(ah_pfkey_q, mp, samsg, ksi, NULL); 1281 break; 1282 case SADB_REGISTER: 1283 /* 1284 * Hmmm, let's do it! Check for extensions (there should 1285 * be none), extract the fields, call ah_register_out(), 1286 * then either free or report an error. 1287 * 1288 * Keysock takes care of the PF_KEY bookkeeping for this. 1289 */ 1290 if (ah_register_out(samsg->sadb_msg_seq, samsg->sadb_msg_pid, 1291 ksi->ks_in_serial)) { 1292 freemsg(mp); 1293 } else { 1294 /* 1295 * Only way this path hits is if there is a memory 1296 * failure. It will not return B_FALSE because of 1297 * lack of ah_pfkey_q if I am in wput(). 1298 */ 1299 sadb_pfkey_error(ah_pfkey_q, mp, ENOMEM, diagnostic, 1300 ksi->ks_in_serial); 1301 } 1302 break; 1303 case SADB_UPDATE: 1304 /* 1305 * Find a larval, if not there, find a full one and get 1306 * strict. 1307 */ 1308 error = ah_update_sa(mp, ksi, &diagnostic); 1309 if (error != 0) { 1310 sadb_pfkey_error(ah_pfkey_q, mp, error, diagnostic, 1311 ksi->ks_in_serial); 1312 } 1313 /* else ah_update_sa() took care of things. */ 1314 break; 1315 case SADB_GETSPI: 1316 /* 1317 * Reserve a new larval entry. 1318 */ 1319 ah_getspi(mp, ksi); 1320 break; 1321 case SADB_ACQUIRE: 1322 /* 1323 * Find larval and/or ACQUIRE record and kill it (them), I'm 1324 * most likely an error. Inbound ACQUIRE messages should only 1325 * have the base header. 1326 */ 1327 sadb_in_acquire(samsg, &ah_sadb, ah_pfkey_q); 1328 freemsg(mp); 1329 break; 1330 case SADB_DUMP: 1331 /* 1332 * Dump all entries. 1333 */ 1334 ah_dump(mp, ksi); 1335 /* ah_dump will take care of the return message, etc. */ 1336 break; 1337 case SADB_EXPIRE: 1338 /* Should never reach me. */ 1339 sadb_pfkey_error(ah_pfkey_q, mp, EOPNOTSUPP, diagnostic, 1340 ksi->ks_in_serial); 1341 break; 1342 default: 1343 sadb_pfkey_error(ah_pfkey_q, mp, EINVAL, 1344 SADB_X_DIAGNOSTIC_UNKNOWN_MSG, ksi->ks_in_serial); 1345 break; 1346 } 1347 } 1348 1349 /* 1350 * Handle case where PF_KEY says it can't find a keysock for one of my 1351 * ACQUIRE messages. 1352 */ 1353 static void 1354 ah_keysock_no_socket(mblk_t *mp) 1355 { 1356 sadb_msg_t *samsg; 1357 keysock_out_err_t *kse = (keysock_out_err_t *)mp->b_rptr; 1358 1359 if (mp->b_cont == NULL) { 1360 freemsg(mp); 1361 return; 1362 } 1363 samsg = (sadb_msg_t *)mp->b_cont->b_rptr; 1364 1365 /* 1366 * If keysock can't find any registered, delete the acquire record 1367 * immediately, and handle errors. 1368 */ 1369 if (samsg->sadb_msg_type == SADB_ACQUIRE) { 1370 samsg->sadb_msg_errno = kse->ks_err_errno; 1371 samsg->sadb_msg_len = SADB_8TO64(sizeof (*samsg)); 1372 /* 1373 * Use the write-side of the ah_pfkey_q, in case there is 1374 * no ah_sadb.s_ip_q. 1375 */ 1376 sadb_in_acquire(samsg, &ah_sadb, WR(ah_pfkey_q)); 1377 } 1378 1379 freemsg(mp); 1380 } 1381 1382 /* 1383 * First-cut reality check for an inbound PF_KEY message. 1384 */ 1385 static boolean_t 1386 ah_pfkey_reality_failures(mblk_t *mp, keysock_in_t *ksi) 1387 { 1388 int diagnostic; 1389 1390 if (mp->b_cont == NULL) { 1391 freemsg(mp); 1392 return (B_TRUE); 1393 } 1394 1395 if (ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT] != NULL) { 1396 diagnostic = SADB_X_DIAGNOSTIC_EKEY_PRESENT; 1397 goto badmsg; 1398 } 1399 if (ksi->ks_in_extv[SADB_EXT_PROPOSAL] != NULL) { 1400 diagnostic = SADB_X_DIAGNOSTIC_PROP_PRESENT; 1401 goto badmsg; 1402 } 1403 if (ksi->ks_in_extv[SADB_EXT_SUPPORTED_AUTH] != NULL || 1404 ksi->ks_in_extv[SADB_EXT_SUPPORTED_ENCRYPT] != NULL) { 1405 diagnostic = SADB_X_DIAGNOSTIC_SUPP_PRESENT; 1406 goto badmsg; 1407 } 1408 if (ksi->ks_in_srctype == KS_IN_ADDR_MBCAST) { 1409 diagnostic = SADB_X_DIAGNOSTIC_BAD_SRC; 1410 goto badmsg; 1411 } 1412 if (ksi->ks_in_dsttype == KS_IN_ADDR_UNSPEC) { 1413 diagnostic = SADB_X_DIAGNOSTIC_BAD_DST; 1414 goto badmsg; 1415 } 1416 1417 return (B_FALSE); /* False ==> no failures */ 1418 1419 badmsg: 1420 sadb_pfkey_error(ah_pfkey_q, mp, EINVAL, diagnostic, ksi->ks_in_serial); 1421 return (B_TRUE); /* True ==> failures */ 1422 } 1423 1424 /* 1425 * AH module write put routine. 1426 */ 1427 static void 1428 ipsecah_wput(queue_t *q, mblk_t *mp) 1429 { 1430 ipsec_info_t *ii; 1431 keysock_in_t *ksi; 1432 int rc; 1433 struct iocblk *iocp; 1434 1435 ah3dbg(("In ah_wput().\n")); 1436 1437 /* NOTE: Each case must take care of freeing or passing mp. */ 1438 switch (mp->b_datap->db_type) { 1439 case M_CTL: 1440 if ((mp->b_wptr - mp->b_rptr) < sizeof (ipsec_info_t)) { 1441 /* Not big enough message. */ 1442 freemsg(mp); 1443 break; 1444 } 1445 ii = (ipsec_info_t *)mp->b_rptr; 1446 1447 switch (ii->ipsec_info_type) { 1448 case KEYSOCK_OUT_ERR: 1449 ah1dbg(("Got KEYSOCK_OUT_ERR message.\n")); 1450 ah_keysock_no_socket(mp); 1451 break; 1452 case KEYSOCK_IN: 1453 AH_BUMP_STAT(keysock_in); 1454 ah3dbg(("Got KEYSOCK_IN message.\n")); 1455 ksi = (keysock_in_t *)ii; 1456 /* 1457 * Some common reality checks. 1458 */ 1459 1460 if (ah_pfkey_reality_failures(mp, ksi)) 1461 return; 1462 1463 /* 1464 * Use 'q' instead of ah_sadb.s_ip_q, since 1465 * it's the write side already, and it'll go 1466 * down to IP. Use ah_pfkey_q because we 1467 * wouldn't get here if that weren't set, and 1468 * the RD(q) has been done already. 1469 */ 1470 if (ksi->ks_in_srctype == KS_IN_ADDR_UNKNOWN) { 1471 rc = sadb_addrcheck(q, ah_pfkey_q, mp, 1472 ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC], 1473 ksi->ks_in_serial); 1474 if (rc == KS_IN_ADDR_UNKNOWN) 1475 return; 1476 else 1477 ksi->ks_in_srctype = rc; 1478 } 1479 if (ksi->ks_in_dsttype == KS_IN_ADDR_UNKNOWN) { 1480 rc = sadb_addrcheck(q, ah_pfkey_q, mp, 1481 ksi->ks_in_extv[SADB_EXT_ADDRESS_DST], 1482 ksi->ks_in_serial); 1483 if (rc == KS_IN_ADDR_UNKNOWN) 1484 return; 1485 else 1486 ksi->ks_in_dsttype = rc; 1487 } 1488 /* 1489 * XXX Proxy may be a different address family. 1490 */ 1491 if (ksi->ks_in_proxytype == KS_IN_ADDR_UNKNOWN) { 1492 rc = sadb_addrcheck(q, ah_pfkey_q, mp, 1493 ksi->ks_in_extv[SADB_EXT_ADDRESS_PROXY], 1494 ksi->ks_in_serial); 1495 if (rc == KS_IN_ADDR_UNKNOWN) 1496 return; 1497 else 1498 ksi->ks_in_proxytype = rc; 1499 } 1500 ah_parse_pfkey(mp); 1501 break; 1502 case KEYSOCK_HELLO: 1503 sadb_keysock_hello(&ah_pfkey_q, q, mp, 1504 ah_ager, &ah_event, SADB_SATYPE_AH); 1505 break; 1506 default: 1507 ah1dbg(("Got M_CTL from above of 0x%x.\n", 1508 ii->ipsec_info_type)); 1509 freemsg(mp); 1510 break; 1511 } 1512 break; 1513 case M_IOCTL: 1514 iocp = (struct iocblk *)mp->b_rptr; 1515 switch (iocp->ioc_cmd) { 1516 case ND_SET: 1517 case ND_GET: 1518 if (nd_getset(q, ipsecah_g_nd, mp)) { 1519 qreply(q, mp); 1520 return; 1521 } else { 1522 iocp->ioc_error = ENOENT; 1523 } 1524 /* FALLTHRU */ 1525 default: 1526 /* We really don't support any other ioctls, do we? */ 1527 1528 /* Return EINVAL */ 1529 if (iocp->ioc_error != ENOENT) 1530 iocp->ioc_error = EINVAL; 1531 iocp->ioc_count = 0; 1532 mp->b_datap->db_type = M_IOCACK; 1533 qreply(q, mp); 1534 return; 1535 } 1536 default: 1537 ah3dbg(("Got default message, type %d, passing to IP.\n", 1538 mp->b_datap->db_type)); 1539 putnext(q, mp); 1540 } 1541 } 1542 1543 /* 1544 * Updating use times can be tricky business if the ipsa_haspeer flag is 1545 * set. This function is called once in an SA's lifetime. 1546 * 1547 * Caller has to REFRELE "assoc" which is passed in. This function has 1548 * to REFRELE any peer SA that is obtained. 1549 */ 1550 static void 1551 ah_set_usetime(ipsa_t *assoc, boolean_t inbound) 1552 { 1553 ipsa_t *inassoc, *outassoc; 1554 isaf_t *bucket; 1555 sadb_t *sp; 1556 int outhash; 1557 boolean_t isv6; 1558 1559 /* No peer? No problem! */ 1560 if (!assoc->ipsa_haspeer) { 1561 sadb_set_usetime(assoc); 1562 return; 1563 } 1564 1565 /* 1566 * Otherwise, we want to grab both the original assoc and its peer. 1567 * There might be a race for this, but if it's a real race, the times 1568 * will be out-of-synch by at most a second, and since our time 1569 * granularity is a second, this won't be a problem. 1570 * 1571 * If we need tight synchronization on the peer SA, then we need to 1572 * reconsider. 1573 */ 1574 1575 /* Use address family to select IPv6/IPv4 */ 1576 isv6 = (assoc->ipsa_addrfam == AF_INET6); 1577 if (isv6) { 1578 sp = &ah_sadb.s_v6; 1579 } else { 1580 sp = &ah_sadb.s_v4; 1581 ASSERT(assoc->ipsa_addrfam == AF_INET); 1582 } 1583 if (inbound) { 1584 inassoc = assoc; 1585 if (isv6) 1586 outhash = OUTBOUND_HASH_V6(sp, *((in6_addr_t *) 1587 &inassoc->ipsa_dstaddr)); 1588 else 1589 outhash = OUTBOUND_HASH_V4(sp, *((ipaddr_t *) 1590 &inassoc->ipsa_dstaddr)); 1591 bucket = &sp->sdb_of[outhash]; 1592 1593 mutex_enter(&bucket->isaf_lock); 1594 outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi, 1595 inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr, 1596 inassoc->ipsa_addrfam); 1597 mutex_exit(&bucket->isaf_lock); 1598 if (outassoc == NULL) { 1599 /* Q: Do we wish to set haspeer == B_FALSE? */ 1600 ah0dbg(("ah_set_usetime: " 1601 "can't find peer for inbound.\n")); 1602 sadb_set_usetime(inassoc); 1603 return; 1604 } 1605 } else { 1606 outassoc = assoc; 1607 bucket = INBOUND_BUCKET(sp, outassoc->ipsa_spi); 1608 mutex_enter(&bucket->isaf_lock); 1609 inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi, 1610 outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr, 1611 outassoc->ipsa_addrfam); 1612 mutex_exit(&bucket->isaf_lock); 1613 if (inassoc == NULL) { 1614 /* Q: Do we wish to set haspeer == B_FALSE? */ 1615 ah0dbg(("ah_set_usetime: " 1616 "can't find peer for outbound.\n")); 1617 sadb_set_usetime(outassoc); 1618 return; 1619 } 1620 } 1621 1622 /* Update usetime on both. */ 1623 sadb_set_usetime(inassoc); 1624 sadb_set_usetime(outassoc); 1625 1626 /* 1627 * REFRELE any peer SA. 1628 * 1629 * Because of the multi-line macro nature of IPSA_REFRELE, keep 1630 * them in { }. 1631 */ 1632 if (inbound) { 1633 IPSA_REFRELE(outassoc); 1634 } else { 1635 IPSA_REFRELE(inassoc); 1636 } 1637 } 1638 1639 /* 1640 * Add a number of bytes to what the SA has protected so far. Return 1641 * B_TRUE if the SA can still protect that many bytes. 1642 * 1643 * Caller must REFRELE the passed-in assoc. This function must REFRELE 1644 * any obtained peer SA. 1645 */ 1646 static boolean_t 1647 ah_age_bytes(ipsa_t *assoc, uint64_t bytes, boolean_t inbound) 1648 { 1649 ipsa_t *inassoc, *outassoc; 1650 isaf_t *bucket; 1651 boolean_t inrc, outrc, isv6; 1652 sadb_t *sp; 1653 int outhash; 1654 1655 /* No peer? No problem! */ 1656 if (!assoc->ipsa_haspeer) { 1657 return (sadb_age_bytes(ah_pfkey_q, assoc, bytes, 1658 B_TRUE)); 1659 } 1660 1661 /* 1662 * Otherwise, we want to grab both the original assoc and its peer. 1663 * There might be a race for this, but if it's a real race, two 1664 * expire messages may occur. We limit this by only sending the 1665 * expire message on one of the peers, we'll pick the inbound 1666 * arbitrarily. 1667 * 1668 * If we need tight synchronization on the peer SA, then we need to 1669 * reconsider. 1670 */ 1671 1672 /* Pick v4/v6 bucket based on addrfam. */ 1673 isv6 = (assoc->ipsa_addrfam == AF_INET6); 1674 if (isv6) { 1675 sp = &ah_sadb.s_v6; 1676 } else { 1677 sp = &ah_sadb.s_v4; 1678 ASSERT(assoc->ipsa_addrfam == AF_INET); 1679 } 1680 if (inbound) { 1681 inassoc = assoc; 1682 if (isv6) 1683 outhash = OUTBOUND_HASH_V6(sp, *((in6_addr_t *) 1684 &inassoc->ipsa_dstaddr)); 1685 else 1686 outhash = OUTBOUND_HASH_V4(sp, *((ipaddr_t *) 1687 &inassoc->ipsa_dstaddr)); 1688 bucket = &sp->sdb_of[outhash]; 1689 mutex_enter(&bucket->isaf_lock); 1690 outassoc = ipsec_getassocbyspi(bucket, inassoc->ipsa_spi, 1691 inassoc->ipsa_srcaddr, inassoc->ipsa_dstaddr, 1692 inassoc->ipsa_addrfam); 1693 mutex_exit(&bucket->isaf_lock); 1694 if (outassoc == NULL) { 1695 /* Q: Do we wish to set haspeer == B_FALSE? */ 1696 ah0dbg(("ah_age_bytes: " 1697 "can't find peer for inbound.\n")); 1698 return (sadb_age_bytes(ah_pfkey_q, inassoc, 1699 bytes, B_TRUE)); 1700 } 1701 } else { 1702 outassoc = assoc; 1703 bucket = INBOUND_BUCKET(sp, outassoc->ipsa_spi); 1704 mutex_enter(&bucket->isaf_lock); 1705 inassoc = ipsec_getassocbyspi(bucket, outassoc->ipsa_spi, 1706 outassoc->ipsa_srcaddr, outassoc->ipsa_dstaddr, 1707 outassoc->ipsa_addrfam); 1708 mutex_exit(&bucket->isaf_lock); 1709 if (inassoc == NULL) { 1710 /* Q: Do we wish to set haspeer == B_FALSE? */ 1711 ah0dbg(("ah_age_bytes: " 1712 "can't find peer for outbound.\n")); 1713 return (sadb_age_bytes(ah_pfkey_q, outassoc, 1714 bytes, B_TRUE)); 1715 } 1716 } 1717 1718 inrc = sadb_age_bytes(ah_pfkey_q, inassoc, bytes, B_TRUE); 1719 outrc = sadb_age_bytes(ah_pfkey_q, outassoc, bytes, B_FALSE); 1720 1721 /* 1722 * REFRELE any peer SA. 1723 * 1724 * Because of the multi-line macro nature of IPSA_REFRELE, keep 1725 * them in { }. 1726 */ 1727 if (inbound) { 1728 IPSA_REFRELE(outassoc); 1729 } else { 1730 IPSA_REFRELE(inassoc); 1731 } 1732 1733 return (inrc && outrc); 1734 } 1735 1736 /* 1737 * Perform the really difficult work of inserting the proposed situation. 1738 * Called while holding the algorithm lock. 1739 */ 1740 static void 1741 ah_insert_prop(sadb_prop_t *prop, ipsacq_t *acqrec, uint_t combs) 1742 { 1743 sadb_comb_t *comb = (sadb_comb_t *)(prop + 1); 1744 ipsec_out_t *io; 1745 ipsec_action_t *ap; 1746 ipsec_prot_t *prot; 1747 io = (ipsec_out_t *)acqrec->ipsacq_mp->b_rptr; 1748 1749 ASSERT(MUTEX_HELD(&alg_lock)); 1750 ASSERT(io->ipsec_out_type == IPSEC_OUT); 1751 1752 prop->sadb_prop_exttype = SADB_EXT_PROPOSAL; 1753 prop->sadb_prop_len = SADB_8TO64(sizeof (sadb_prop_t)); 1754 *(uint32_t *)(&prop->sadb_prop_replay) = 0; /* Quick zero-out! */ 1755 1756 prop->sadb_prop_replay = ipsecah_replay_size; 1757 1758 /* 1759 * Based upon algorithm properties, and what-not, prioritize a 1760 * proposal, based on the ordering of the ah algorithms in the 1761 * alternatives presented in the policy rule passed down 1762 * through the ipsec_out_t and attached to the acquire record. 1763 */ 1764 1765 for (ap = acqrec->ipsacq_act; ap != NULL; 1766 ap = ap->ipa_next) { 1767 ipsec_alginfo_t *aalg; 1768 1769 if ((ap->ipa_act.ipa_type != IPSEC_POLICY_APPLY) || 1770 (!ap->ipa_act.ipa_apply.ipp_use_ah)) 1771 continue; 1772 1773 prot = &ap->ipa_act.ipa_apply; 1774 1775 ASSERT(prot->ipp_auth_alg > 0); 1776 1777 aalg = ipsec_alglists[IPSEC_ALG_AUTH][prot->ipp_auth_alg]; 1778 if (aalg == NULL || !ALG_VALID(aalg)) 1779 continue; 1780 1781 /* XXX check aalg for duplicates??.. */ 1782 1783 comb->sadb_comb_flags = 0; 1784 comb->sadb_comb_reserved = 0; 1785 comb->sadb_comb_encrypt = 0; 1786 comb->sadb_comb_encrypt_minbits = 0; 1787 comb->sadb_comb_encrypt_maxbits = 0; 1788 1789 comb->sadb_comb_auth = aalg->alg_id; 1790 comb->sadb_comb_auth_minbits = prot->ipp_ah_minbits; 1791 comb->sadb_comb_auth_maxbits = prot->ipp_ah_maxbits; 1792 1793 /* 1794 * The following may be based on algorithm 1795 * properties, but in the meantime, we just pick 1796 * some good, sensible numbers. Key mgmt. can 1797 * (and perhaps should) be the place to finalize 1798 * such decisions. 1799 */ 1800 1801 /* 1802 * No limits on allocations, since we really don't 1803 * support that concept currently. 1804 */ 1805 comb->sadb_comb_soft_allocations = 0; 1806 comb->sadb_comb_hard_allocations = 0; 1807 1808 /* 1809 * These may want to come from policy rule.. 1810 */ 1811 comb->sadb_comb_soft_bytes = ipsecah_default_soft_bytes; 1812 comb->sadb_comb_hard_bytes = ipsecah_default_hard_bytes; 1813 comb->sadb_comb_soft_addtime = ipsecah_default_soft_addtime; 1814 comb->sadb_comb_hard_addtime = ipsecah_default_hard_addtime; 1815 comb->sadb_comb_soft_usetime = ipsecah_default_soft_usetime; 1816 comb->sadb_comb_hard_usetime = ipsecah_default_hard_usetime; 1817 1818 prop->sadb_prop_len += SADB_8TO64(sizeof (*comb)); 1819 if (--combs == 0) 1820 return; /* out of space.. */ 1821 comb++; 1822 } 1823 } 1824 1825 /* 1826 * Prepare and actually send the SADB_ACQUIRE message to PF_KEY. 1827 */ 1828 static void 1829 ah_send_acquire(ipsacq_t *acqrec, mblk_t *extended) 1830 { 1831 mblk_t *pfkeymp, *msgmp; 1832 uint_t allocsize, combs; 1833 sadb_msg_t *samsg; 1834 sadb_prop_t *prop; 1835 uint8_t *cur, *end; 1836 1837 AH_BUMP_STAT(acquire_requests); 1838 1839 ASSERT(MUTEX_HELD(&acqrec->ipsacq_lock)); 1840 1841 pfkeymp = sadb_keysock_out(0); 1842 if (pfkeymp == NULL) { 1843 ah1dbg(("ah_send_acquire: 1st allocb() failed.\n")); 1844 /* Just bail. */ 1845 goto done; 1846 } 1847 1848 /* 1849 * First, allocate a basic ACQUIRE message. Beyond that, 1850 * you need to extract certificate info from 1851 */ 1852 allocsize = sizeof (sadb_msg_t) + sizeof (sadb_address_t) + 1853 sizeof (sadb_address_t) + sizeof (sadb_prop_t); 1854 1855 switch (acqrec->ipsacq_addrfam) { 1856 case AF_INET: 1857 allocsize += 2 * sizeof (struct sockaddr_in); 1858 break; 1859 case AF_INET6: 1860 allocsize += 2 * sizeof (struct sockaddr_in6); 1861 break; 1862 } 1863 1864 mutex_enter(&alg_lock); 1865 1866 combs = ipsec_nalgs[IPSEC_ALG_AUTH]; 1867 1868 allocsize += combs * sizeof (sadb_comb_t); 1869 1870 /* 1871 * XXX If there are: 1872 * certificate IDs 1873 * proxy address 1874 * <Others> 1875 * add additional allocation size. 1876 */ 1877 1878 msgmp = allocb(allocsize, BPRI_HI); 1879 if (msgmp == NULL) { 1880 ah0dbg(("ah_send_acquire: 2nd allocb() failed.\n")); 1881 /* Just bail. */ 1882 freemsg(pfkeymp); 1883 pfkeymp = NULL; 1884 goto done; 1885 } 1886 1887 cur = msgmp->b_rptr; 1888 end = cur + allocsize; 1889 samsg = (sadb_msg_t *)cur; 1890 pfkeymp->b_cont = msgmp; 1891 1892 /* Set up ACQUIRE. */ 1893 cur = sadb_setup_acquire(cur, end, acqrec); 1894 if (cur == NULL) { 1895 ah0dbg(("sadb_setup_acquire failed.\n")); 1896 /* Just bail. */ 1897 freemsg(pfkeymp); 1898 pfkeymp = NULL; 1899 goto done; 1900 } 1901 samsg->sadb_msg_satype = SADB_SATYPE_AH; 1902 1903 /* XXX Insert proxy address information here. */ 1904 1905 /* XXX Insert identity information here. */ 1906 1907 /* XXXMLS Insert sensitivity information here. */ 1908 1909 /* Insert proposal here. */ 1910 1911 prop = (sadb_prop_t *)(((uint64_t *)samsg) + samsg->sadb_msg_len); 1912 ah_insert_prop(prop, acqrec, combs); 1913 samsg->sadb_msg_len += prop->sadb_prop_len; 1914 msgmp->b_wptr += SADB_64TO8(samsg->sadb_msg_len); 1915 1916 done: 1917 mutex_exit(&alg_lock); 1918 1919 /* 1920 * Must mutex_exit() before sending PF_KEY message up, in 1921 * order to avoid recursive mutex_enter() if there are no registered 1922 * listeners. 1923 * 1924 * Once I've sent the message, I'm cool anyway. 1925 */ 1926 mutex_exit(&acqrec->ipsacq_lock); 1927 if (ah_pfkey_q != NULL && pfkeymp != NULL) { 1928 if (extended != NULL) { 1929 putnext(ah_pfkey_q, extended); 1930 } 1931 putnext(ah_pfkey_q, pfkeymp); 1932 return; 1933 } 1934 /* NOTE: freemsg() works for extended == NULL. */ 1935 freemsg(extended); 1936 freemsg(pfkeymp); 1937 } 1938 1939 /* 1940 * Handle the SADB_GETSPI message. Create a larval SA. 1941 */ 1942 static void 1943 ah_getspi(mblk_t *mp, keysock_in_t *ksi) 1944 { 1945 ipsa_t *newbie, *target; 1946 isaf_t *outbound, *inbound; 1947 int rc, diagnostic; 1948 sadb_sa_t *assoc; 1949 keysock_out_t *kso; 1950 uint32_t newspi; 1951 1952 /* 1953 * Randomly generate a proposed SPI value. 1954 */ 1955 (void) random_get_pseudo_bytes((uint8_t *)&newspi, sizeof (uint32_t)); 1956 newbie = sadb_getspi(ksi, newspi, &diagnostic); 1957 1958 if (newbie == NULL) { 1959 sadb_pfkey_error(ah_pfkey_q, mp, ENOMEM, diagnostic, 1960 ksi->ks_in_serial); 1961 return; 1962 } else if (newbie == (ipsa_t *)-1) { 1963 sadb_pfkey_error(ah_pfkey_q, mp, EINVAL, diagnostic, 1964 ksi->ks_in_serial); 1965 return; 1966 } 1967 1968 /* 1969 * XXX - We may randomly collide. We really should recover from this. 1970 * Unfortunately, that could require spending way-too-much-time 1971 * in here. For now, let the user retry. 1972 */ 1973 1974 if (newbie->ipsa_addrfam == AF_INET6) { 1975 outbound = OUTBOUND_BUCKET_V6(&ah_sadb.s_v6, 1976 *(uint32_t *)(newbie->ipsa_dstaddr)); 1977 inbound = INBOUND_BUCKET(&ah_sadb.s_v6, newbie->ipsa_spi); 1978 } else { 1979 outbound = OUTBOUND_BUCKET_V4(&ah_sadb.s_v4, 1980 *(uint32_t *)(newbie->ipsa_dstaddr)); 1981 inbound = INBOUND_BUCKET(&ah_sadb.s_v4, newbie->ipsa_spi); 1982 } 1983 1984 mutex_enter(&outbound->isaf_lock); 1985 mutex_enter(&inbound->isaf_lock); 1986 1987 /* 1988 * Check for collisions (i.e. did sadb_getspi() return with something 1989 * that already exists?). 1990 * 1991 * Try outbound first. Even though SADB_GETSPI is traditionally 1992 * for inbound SAs, you never know what a user might do. 1993 */ 1994 target = ipsec_getassocbyspi(outbound, newbie->ipsa_spi, 1995 newbie->ipsa_srcaddr, newbie->ipsa_dstaddr, newbie->ipsa_addrfam); 1996 if (target == NULL) { 1997 target = ipsec_getassocbyspi(inbound, newbie->ipsa_spi, 1998 newbie->ipsa_srcaddr, newbie->ipsa_dstaddr, 1999 newbie->ipsa_addrfam); 2000 } 2001 2002 /* 2003 * I don't have collisions elsewhere! 2004 * (Nor will I because I'm still holding inbound/outbound locks.) 2005 */ 2006 2007 if (target != NULL) { 2008 rc = EEXIST; 2009 IPSA_REFRELE(target); 2010 } else { 2011 /* 2012 * sadb_insertassoc() also checks for collisions, so 2013 * if there's a colliding larval entry, rc will be set 2014 * to EEXIST. 2015 */ 2016 rc = sadb_insertassoc(newbie, inbound); 2017 (void) drv_getparm(TIME, &newbie->ipsa_hardexpiretime); 2018 newbie->ipsa_hardexpiretime += ipsecah_larval_timeout; 2019 } 2020 2021 /* 2022 * Can exit outbound mutex. Hold inbound until we're done with 2023 * newbie. 2024 */ 2025 mutex_exit(&outbound->isaf_lock); 2026 2027 if (rc != 0) { 2028 mutex_exit(&inbound->isaf_lock); 2029 IPSA_REFRELE(newbie); 2030 sadb_pfkey_error(ah_pfkey_q, mp, rc, SADB_X_DIAGNOSTIC_NONE, 2031 ksi->ks_in_serial); 2032 return; 2033 } 2034 2035 /* Can write here because I'm still holding the bucket lock. */ 2036 newbie->ipsa_type = SADB_SATYPE_AH; 2037 2038 /* 2039 * Construct successful return message. We have one thing going 2040 * for us in PF_KEY v2. That's the fact that 2041 * sizeof (sadb_spirange_t) == sizeof (sadb_sa_t) 2042 */ 2043 assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SPIRANGE]; 2044 assoc->sadb_sa_exttype = SADB_EXT_SA; 2045 assoc->sadb_sa_spi = newbie->ipsa_spi; 2046 *((uint64_t *)(&assoc->sadb_sa_replay)) = 0; 2047 mutex_exit(&inbound->isaf_lock); 2048 2049 /* Convert KEYSOCK_IN to KEYSOCK_OUT. */ 2050 kso = (keysock_out_t *)ksi; 2051 kso->ks_out_len = sizeof (*kso); 2052 kso->ks_out_serial = ksi->ks_in_serial; 2053 kso->ks_out_type = KEYSOCK_OUT; 2054 2055 /* 2056 * Can safely putnext() to ah_pfkey_q, because this is a turnaround 2057 * from the ah_pfkey_q. 2058 */ 2059 putnext(ah_pfkey_q, mp); 2060 } 2061 2062 /* 2063 * IPv6 sends up the ICMP errors for validation and the removal of the AH 2064 * header. 2065 */ 2066 static ipsec_status_t 2067 ah_icmp_error_v6(mblk_t *ipsec_mp) 2068 { 2069 mblk_t *mp; 2070 ip6_t *ip6h, *oip6h; 2071 uint16_t hdr_length, ah_length; 2072 uint8_t *nexthdrp; 2073 ah_t *ah; 2074 icmp6_t *icmp6; 2075 isaf_t *isaf; 2076 ipsa_t *assoc; 2077 uint8_t *post_ah_ptr; 2078 2079 mp = ipsec_mp->b_cont; 2080 ASSERT(mp->b_datap->db_type == M_CTL); 2081 2082 /* 2083 * Change the type to M_DATA till we finish pullups. 2084 */ 2085 mp->b_datap->db_type = M_DATA; 2086 2087 /* 2088 * Eat the cost of a pullupmsg() for now. It makes the rest of this 2089 * code far less convoluted. 2090 */ 2091 if (!pullupmsg(mp, -1) || 2092 !ip_hdr_length_nexthdr_v6(mp, (ip6_t *)mp->b_rptr, &hdr_length, 2093 &nexthdrp) || 2094 mp->b_rptr + hdr_length + sizeof (icmp6_t) + sizeof (ip6_t) + 2095 sizeof (ah_t) > mp->b_wptr) { 2096 IP_AH_BUMP_STAT(in_discards); 2097 ip_drop_packet(ipsec_mp, B_TRUE, NULL, NULL, &ipdrops_ah_nomem, 2098 &ah_dropper); 2099 return (IPSEC_STATUS_FAILED); 2100 } 2101 2102 oip6h = (ip6_t *)mp->b_rptr; 2103 icmp6 = (icmp6_t *)((uint8_t *)oip6h + hdr_length); 2104 ip6h = (ip6_t *)(icmp6 + 1); 2105 if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_length, &nexthdrp)) { 2106 IP_AH_BUMP_STAT(in_discards); 2107 ip_drop_packet(ipsec_mp, B_TRUE, NULL, NULL, 2108 &ipdrops_ah_bad_v6_hdrs, &ah_dropper); 2109 return (IPSEC_STATUS_FAILED); 2110 } 2111 ah = (ah_t *)((uint8_t *)ip6h + hdr_length); 2112 2113 isaf = OUTBOUND_BUCKET_V6(&ah_sadb.s_v6, ip6h->ip6_dst); 2114 mutex_enter(&isaf->isaf_lock); 2115 assoc = ipsec_getassocbyspi(isaf, ah->ah_spi, 2116 (uint32_t *)&ip6h->ip6_src, (uint32_t *)&ip6h->ip6_dst, AF_INET6); 2117 mutex_exit(&isaf->isaf_lock); 2118 2119 if (assoc == NULL) { 2120 IP_AH_BUMP_STAT(lookup_failure); 2121 IP_AH_BUMP_STAT(in_discards); 2122 if (ipsecah_log_unknown_spi) { 2123 ipsec_assocfailure(info.mi_idnum, 0, 0, 2124 SL_CONSOLE | SL_WARN | SL_ERROR, 2125 "Bad ICMP message - No association for the " 2126 "attached AH header whose spi is 0x%x, " 2127 "sender is 0x%x\n", 2128 ah->ah_spi, &oip6h->ip6_src, AF_INET6); 2129 } 2130 ip_drop_packet(ipsec_mp, B_TRUE, NULL, NULL, &ipdrops_ah_no_sa, 2131 &ah_dropper); 2132 return (IPSEC_STATUS_FAILED); 2133 } 2134 2135 IPSA_REFRELE(assoc); 2136 2137 /* 2138 * There seems to be a valid association. If there is enough of AH 2139 * header remove it, otherwise bail. One could check whether it has 2140 * complete AH header plus 8 bytes but it does not make sense if an 2141 * icmp error is returned for ICMP messages e.g ICMP time exceeded, 2142 * that are being sent up. Let the caller figure out. 2143 * 2144 * NOTE: ah_length is the number of 32 bit words minus 2. 2145 */ 2146 ah_length = (ah->ah_length << 2) + 8; 2147 post_ah_ptr = (uint8_t *)ah + ah_length; 2148 2149 if (post_ah_ptr > mp->b_wptr) { 2150 IP_AH_BUMP_STAT(in_discards); 2151 ip_drop_packet(ipsec_mp, B_TRUE, NULL, NULL, 2152 &ipdrops_ah_bad_length, &ah_dropper); 2153 return (IPSEC_STATUS_FAILED); 2154 } 2155 2156 ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - ah_length); 2157 *nexthdrp = ah->ah_nexthdr; 2158 ovbcopy(post_ah_ptr, ah, 2159 (size_t)((uintptr_t)mp->b_wptr - (uintptr_t)post_ah_ptr)); 2160 mp->b_wptr -= ah_length; 2161 /* Rewhack to be an ICMP error. */ 2162 mp->b_datap->db_type = M_CTL; 2163 2164 return (IPSEC_STATUS_SUCCESS); 2165 } 2166 2167 /* 2168 * IP sends up the ICMP errors for validation and the removal of 2169 * the AH header. 2170 */ 2171 static ipsec_status_t 2172 ah_icmp_error_v4(mblk_t *ipsec_mp) 2173 { 2174 mblk_t *mp; 2175 mblk_t *mp1; 2176 icmph_t *icmph; 2177 int iph_hdr_length; 2178 int hdr_length; 2179 isaf_t *hptr; 2180 ipsa_t *assoc; 2181 int ah_length; 2182 ipha_t *ipha; 2183 ipha_t *oipha; 2184 ah_t *ah; 2185 uint32_t length; 2186 int alloc_size; 2187 uint8_t nexthdr; 2188 2189 mp = ipsec_mp->b_cont; 2190 ASSERT(mp->b_datap->db_type == M_CTL); 2191 2192 /* 2193 * Change the type to M_DATA till we finish pullups. 2194 */ 2195 mp->b_datap->db_type = M_DATA; 2196 2197 oipha = ipha = (ipha_t *)mp->b_rptr; 2198 iph_hdr_length = IPH_HDR_LENGTH(ipha); 2199 icmph = (icmph_t *)&mp->b_rptr[iph_hdr_length]; 2200 2201 ipha = (ipha_t *)&icmph[1]; 2202 hdr_length = IPH_HDR_LENGTH(ipha); 2203 2204 /* 2205 * See if we have enough to locate the SPI 2206 */ 2207 if ((uchar_t *)ipha + hdr_length + 8 > mp->b_wptr) { 2208 if (!pullupmsg(mp, (uchar_t *)ipha + hdr_length + 8 - 2209 mp->b_rptr)) { 2210 ipsec_rl_strlog(info.mi_idnum, 0, 0, 2211 SL_WARN | SL_ERROR, 2212 "ICMP error: Small AH header\n"); 2213 IP_AH_BUMP_STAT(in_discards); 2214 ip_drop_packet(ipsec_mp, B_TRUE, NULL, NULL, 2215 &ipdrops_ah_bad_length, &ah_dropper); 2216 return (IPSEC_STATUS_FAILED); 2217 } 2218 icmph = (icmph_t *)&mp->b_rptr[iph_hdr_length]; 2219 ipha = (ipha_t *)&icmph[1]; 2220 } 2221 2222 ah = (ah_t *)((uint8_t *)ipha + hdr_length); 2223 nexthdr = ah->ah_nexthdr; 2224 2225 hptr = OUTBOUND_BUCKET_V4(&ah_sadb.s_v4, ipha->ipha_dst); 2226 mutex_enter(&hptr->isaf_lock); 2227 assoc = ipsec_getassocbyspi(hptr, ah->ah_spi, 2228 (uint32_t *)&ipha->ipha_src, (uint32_t *)&ipha->ipha_dst, AF_INET); 2229 mutex_exit(&hptr->isaf_lock); 2230 2231 if (assoc == NULL) { 2232 IP_AH_BUMP_STAT(lookup_failure); 2233 IP_AH_BUMP_STAT(in_discards); 2234 if (ipsecah_log_unknown_spi) { 2235 ipsec_assocfailure(info.mi_idnum, 0, 0, 2236 SL_CONSOLE | SL_WARN | SL_ERROR, 2237 "Bad ICMP message - No association for the " 2238 "attached AH header whose spi is 0x%x, " 2239 "sender is 0x%x\n", 2240 ah->ah_spi, &oipha->ipha_src, AF_INET); 2241 } 2242 ip_drop_packet(ipsec_mp, B_TRUE, NULL, NULL, &ipdrops_ah_no_sa, 2243 &ah_dropper); 2244 return (IPSEC_STATUS_FAILED); 2245 } 2246 2247 IPSA_REFRELE(assoc); 2248 /* 2249 * There seems to be a valid association. If there 2250 * is enough of AH header remove it, otherwise remove 2251 * as much as possible and send it back. One could check 2252 * whether it has complete AH header plus 8 bytes but it 2253 * does not make sense if an icmp error is returned for 2254 * ICMP messages e.g ICMP time exceeded, that are being 2255 * sent up. Let the caller figure out. 2256 * 2257 * NOTE: ah_length is the number of 32 bit words minus 2. 2258 */ 2259 ah_length = (ah->ah_length << 2) + 8; 2260 2261 if ((uchar_t *)ipha + hdr_length + ah_length > mp->b_wptr) { 2262 if (mp->b_cont == NULL) { 2263 /* 2264 * There is nothing to pullup. Just remove as 2265 * much as possible. This is a common case for 2266 * IPV4. 2267 */ 2268 ah_length = (mp->b_wptr - ((uchar_t *)ipha + 2269 hdr_length)); 2270 goto done; 2271 } 2272 /* Pullup the full ah header */ 2273 if (!pullupmsg(mp, (uchar_t *)ah + ah_length - mp->b_rptr)) { 2274 /* 2275 * pullupmsg could have failed if there was not 2276 * enough to pullup or memory allocation failed. 2277 * We tried hard, give up now. 2278 */ 2279 IP_AH_BUMP_STAT(in_discards); 2280 ip_drop_packet(ipsec_mp, B_TRUE, NULL, NULL, 2281 &ipdrops_ah_nomem, &ah_dropper); 2282 return (IPSEC_STATUS_FAILED); 2283 } 2284 icmph = (icmph_t *)&mp->b_rptr[iph_hdr_length]; 2285 ipha = (ipha_t *)&icmph[1]; 2286 } 2287 done: 2288 /* 2289 * Remove the AH header and change the protocol. 2290 * Don't update the spi fields in the ipsec_in 2291 * message as we are called just to validate the 2292 * message attached to the ICMP message. 2293 * 2294 * If we never pulled up since all of the message 2295 * is in one single mblk, we can't remove the AH header 2296 * by just setting the b_wptr to the beginning of the 2297 * AH header. We need to allocate a mblk that can hold 2298 * up until the inner IP header and copy them. 2299 */ 2300 alloc_size = iph_hdr_length + sizeof (icmph_t) + hdr_length; 2301 2302 if ((mp1 = allocb(alloc_size, BPRI_LO)) == NULL) { 2303 IP_AH_BUMP_STAT(in_discards); 2304 ip_drop_packet(ipsec_mp, B_TRUE, NULL, NULL, &ipdrops_ah_nomem, 2305 &ah_dropper); 2306 return (IPSEC_STATUS_FAILED); 2307 } 2308 /* ICMP errors are M_CTL messages */ 2309 mp1->b_datap->db_type = M_CTL; 2310 ipsec_mp->b_cont = mp1; 2311 bcopy(mp->b_rptr, mp1->b_rptr, alloc_size); 2312 mp1->b_wptr += alloc_size; 2313 2314 /* 2315 * Skip whatever we have copied and as much of AH header 2316 * possible. If we still have something left in the original 2317 * message, tag on. 2318 */ 2319 mp->b_rptr = (uchar_t *)ipha + hdr_length + ah_length; 2320 2321 if (mp->b_rptr != mp->b_wptr) { 2322 mp1->b_cont = mp; 2323 } else { 2324 if (mp->b_cont != NULL) 2325 mp1->b_cont = mp->b_cont; 2326 freeb(mp); 2327 } 2328 2329 ipha = (ipha_t *)(mp1->b_rptr + iph_hdr_length + sizeof (icmph_t)); 2330 ipha->ipha_protocol = nexthdr; 2331 length = ntohs(ipha->ipha_length); 2332 length -= ah_length; 2333 ipha->ipha_length = htons((uint16_t)length); 2334 ipha->ipha_hdr_checksum = 0; 2335 ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha); 2336 2337 return (IPSEC_STATUS_SUCCESS); 2338 } 2339 2340 /* 2341 * IP calls this to validate the ICMP errors that 2342 * we got from the network. 2343 */ 2344 ipsec_status_t 2345 ipsecah_icmp_error(mblk_t *mp) 2346 { 2347 ipsec_in_t *ii = (ipsec_in_t *)mp->b_rptr; 2348 2349 if (ii->ipsec_in_v4) 2350 return (ah_icmp_error_v4(mp)); 2351 else 2352 return (ah_icmp_error_v6(mp)); 2353 } 2354 2355 static int 2356 ah_fix_tlv_options_v6(uint8_t *oi_opt, uint8_t *pi_opt, uint_t ehdrlen, 2357 uint8_t hdr_type, boolean_t copy_always) 2358 { 2359 uint8_t opt_type; 2360 uint_t optlen; 2361 2362 ASSERT(hdr_type == IPPROTO_DSTOPTS || hdr_type == IPPROTO_HOPOPTS); 2363 2364 /* 2365 * Copy the next header and hdr ext. len of the HOP-by-HOP 2366 * and Destination option. 2367 */ 2368 *pi_opt++ = *oi_opt++; 2369 *pi_opt++ = *oi_opt++; 2370 ehdrlen -= 2; 2371 2372 /* 2373 * Now handle all the TLV encoded options. 2374 */ 2375 while (ehdrlen != 0) { 2376 opt_type = *oi_opt; 2377 2378 if (opt_type == IP6OPT_PAD1) { 2379 optlen = 1; 2380 } else { 2381 if (ehdrlen < 2) 2382 goto bad_opt; 2383 optlen = 2 + oi_opt[1]; 2384 if (optlen > ehdrlen) 2385 goto bad_opt; 2386 } 2387 if (copy_always || !(opt_type & IP6OPT_MUTABLE)) { 2388 bcopy(oi_opt, pi_opt, optlen); 2389 } else { 2390 if (optlen == 1) { 2391 *pi_opt = 0; 2392 } else { 2393 /* 2394 * Copy the type and data length fields. 2395 * Zero the option data by skipping 2396 * option type and option data len 2397 * fields. 2398 */ 2399 *pi_opt = *oi_opt; 2400 *(pi_opt + 1) = *(oi_opt + 1); 2401 bzero(pi_opt + 2, optlen - 2); 2402 } 2403 } 2404 ehdrlen -= optlen; 2405 oi_opt += optlen; 2406 pi_opt += optlen; 2407 } 2408 return (0); 2409 bad_opt: 2410 return (-1); 2411 } 2412 2413 /* 2414 * Construct a pseudo header for AH, processing all the options. 2415 * 2416 * oip6h is the IPv6 header of the incoming or outgoing packet. 2417 * ip6h is the pointer to the pseudo headers IPV6 header. All 2418 * the space needed for the options have been allocated including 2419 * the AH header. 2420 * 2421 * If copy_always is set, all the options that appear before AH are copied 2422 * blindly without checking for IP6OPT_MUTABLE. This is used by 2423 * ah_auth_out_done(). Please refer to that function for details. 2424 * 2425 * NOTE : 2426 * 2427 * * AH header is never copied in this function even if copy_always 2428 * is set. It just returns the ah_offset - offset of the AH header 2429 * and the caller needs to do the copying. This is done so that we 2430 * don't have pass extra arguments e.g. SA etc. and also, 2431 * it is not needed when ah_auth_out_done is calling this function. 2432 */ 2433 static uint_t 2434 ah_fix_phdr_v6(ip6_t *ip6h, ip6_t *oip6h, boolean_t outbound, 2435 boolean_t copy_always) 2436 { 2437 uint8_t *oi_opt; 2438 uint8_t *pi_opt; 2439 uint8_t nexthdr; 2440 uint8_t *prev_nexthdr; 2441 ip6_hbh_t *hbhhdr; 2442 ip6_dest_t *dsthdr = NULL; 2443 ip6_rthdr0_t *rthdr; 2444 int ehdrlen; 2445 ah_t *ah; 2446 int ret; 2447 2448 /* 2449 * In the outbound case for source route, ULP has already moved 2450 * the first hop, which is now in ip6_dst. We need to re-arrange 2451 * the header to make it look like how it would appear in the 2452 * receiver i.e 2453 * 2454 * Because of ip_massage_options_v6 the header looks like 2455 * this : 2456 * 2457 * ip6_src = S, ip6_dst = I1. followed by I2,I3,D. 2458 * 2459 * When it reaches the receiver, it would look like 2460 * 2461 * ip6_src = S, ip6_dst = D. followed by I1,I2,I3. 2462 * 2463 * NOTE : We assume that there are no problems with the options 2464 * as IP should have already checked this. 2465 */ 2466 2467 oi_opt = (uchar_t *)&oip6h[1]; 2468 pi_opt = (uchar_t *)&ip6h[1]; 2469 2470 /* 2471 * We set the prev_nexthdr properly in the pseudo header. 2472 * After we finish authentication and come back from the 2473 * algorithm module, pseudo header will become the real 2474 * IP header. 2475 */ 2476 prev_nexthdr = (uint8_t *)&ip6h->ip6_nxt; 2477 nexthdr = oip6h->ip6_nxt; 2478 /* Assume IP has already stripped it */ 2479 ASSERT(nexthdr != IPPROTO_FRAGMENT && nexthdr != IPPROTO_RAW); 2480 ah = NULL; 2481 dsthdr = NULL; 2482 for (;;) { 2483 switch (nexthdr) { 2484 case IPPROTO_HOPOPTS: 2485 hbhhdr = (ip6_hbh_t *)oi_opt; 2486 nexthdr = hbhhdr->ip6h_nxt; 2487 ehdrlen = 8 * (hbhhdr->ip6h_len + 1); 2488 ret = ah_fix_tlv_options_v6(oi_opt, pi_opt, ehdrlen, 2489 IPPROTO_HOPOPTS, copy_always); 2490 /* 2491 * Return a zero offset indicating error if there 2492 * was error. 2493 */ 2494 if (ret == -1) 2495 return (0); 2496 hbhhdr = (ip6_hbh_t *)pi_opt; 2497 prev_nexthdr = (uint8_t *)&hbhhdr->ip6h_nxt; 2498 break; 2499 case IPPROTO_ROUTING: 2500 rthdr = (ip6_rthdr0_t *)oi_opt; 2501 nexthdr = rthdr->ip6r0_nxt; 2502 ehdrlen = 8 * (rthdr->ip6r0_len + 1); 2503 if (!copy_always && outbound) { 2504 int i, left; 2505 ip6_rthdr0_t *prthdr; 2506 in6_addr_t *ap, *pap; 2507 2508 left = rthdr->ip6r0_segleft; 2509 prthdr = (ip6_rthdr0_t *)pi_opt; 2510 pap = (in6_addr_t *)(prthdr + 1); 2511 ap = (in6_addr_t *)(rthdr + 1); 2512 /* 2513 * First eight bytes except seg_left 2514 * does not change en route. 2515 */ 2516 bcopy(oi_opt, pi_opt, 8); 2517 prthdr->ip6r0_segleft = 0; 2518 /* 2519 * First address has been moved to 2520 * the destination address of the 2521 * ip header by ip_massage_options_v6. 2522 * And the real destination address is 2523 * in the last address part of the 2524 * option. 2525 */ 2526 *pap = oip6h->ip6_dst; 2527 for (i = 1; i < left - 1; i++) 2528 pap[i] = ap[i - 1]; 2529 ip6h->ip6_dst = *(ap + left - 1); 2530 } else { 2531 bcopy(oi_opt, pi_opt, ehdrlen); 2532 } 2533 rthdr = (ip6_rthdr0_t *)pi_opt; 2534 prev_nexthdr = (uint8_t *)&rthdr->ip6r0_nxt; 2535 break; 2536 case IPPROTO_DSTOPTS: 2537 /* 2538 * Destination options are tricky. If there is 2539 * a terminal (e.g. non-IPv6-extension) header 2540 * following the destination options, don't 2541 * reset prev_nexthdr or advance the AH insertion 2542 * point and just treat this as a terminal header. 2543 * 2544 * If this is an inbound packet, just deal with 2545 * it as is. 2546 */ 2547 dsthdr = (ip6_dest_t *)oi_opt; 2548 /* 2549 * XXX I hope common-subexpression elimination 2550 * saves us the double-evaluate. 2551 */ 2552 if (outbound && dsthdr->ip6d_nxt != IPPROTO_ROUTING && 2553 dsthdr->ip6d_nxt != IPPROTO_HOPOPTS) 2554 goto terminal_hdr; 2555 nexthdr = dsthdr->ip6d_nxt; 2556 ehdrlen = 8 * (dsthdr->ip6d_len + 1); 2557 ret = ah_fix_tlv_options_v6(oi_opt, pi_opt, ehdrlen, 2558 IPPROTO_DSTOPTS, copy_always); 2559 /* 2560 * Return a zero offset indicating error if there 2561 * was error. 2562 */ 2563 if (ret == -1) 2564 return (0); 2565 break; 2566 case IPPROTO_AH: 2567 /* 2568 * Be conservative in what you send. We shouldn't 2569 * see two same-scoped AH's in one packet. 2570 * (Inner-IP-scoped AH will be hit by terminal 2571 * header of IP or IPv6.) 2572 */ 2573 ASSERT(!outbound); 2574 return ((uint_t)(pi_opt - (uint8_t *)ip6h)); 2575 default: 2576 ASSERT(outbound); 2577 terminal_hdr: 2578 *prev_nexthdr = IPPROTO_AH; 2579 ah = (ah_t *)pi_opt; 2580 ah->ah_nexthdr = nexthdr; 2581 return ((uint_t)(pi_opt - (uint8_t *)ip6h)); 2582 } 2583 pi_opt += ehdrlen; 2584 oi_opt += ehdrlen; 2585 } 2586 /* NOTREACHED */ 2587 } 2588 2589 static boolean_t 2590 ah_finish_up(ah_t *phdr_ah, ah_t *inbound_ah, ipsa_t *assoc, 2591 int ah_data_sz, int ah_align_sz) 2592 { 2593 int i; 2594 2595 /* 2596 * Padding : 2597 * 2598 * 1) Authentication data may have to be padded 2599 * before ICV calculation if ICV is not a multiple 2600 * of 64 bits. This padding is arbitrary and transmitted 2601 * with the packet at the end of the authentication data. 2602 * Payload length should include the padding bytes. 2603 * 2604 * 2) Explicit padding of the whole datagram may be 2605 * required by the algorithm which need not be 2606 * transmitted. It is assumed that this will be taken 2607 * care by the algorithm module. 2608 */ 2609 bzero(phdr_ah + 1, ah_data_sz); /* Zero out ICV for pseudo-hdr. */ 2610 2611 if (inbound_ah == NULL) { 2612 /* Outbound AH datagram. */ 2613 2614 phdr_ah->ah_length = (ah_align_sz >> 2) + 1; 2615 phdr_ah->ah_reserved = 0; 2616 phdr_ah->ah_spi = assoc->ipsa_spi; 2617 2618 phdr_ah->ah_replay = 2619 htonl(atomic_add_32_nv(&assoc->ipsa_replay, 1)); 2620 if (phdr_ah->ah_replay == 0 && assoc->ipsa_replay_wsize != 0) { 2621 /* 2622 * XXX We have replay counter wrapping. We probably 2623 * want to nuke this SA (and its peer). 2624 */ 2625 ipsec_assocfailure(info.mi_idnum, 0, 0, 2626 SL_ERROR | SL_CONSOLE | SL_WARN, 2627 "Outbound AH SA (0x%x), dst %s has wrapped " 2628 "sequence.\n", phdr_ah->ah_spi, 2629 assoc->ipsa_dstaddr, assoc->ipsa_addrfam); 2630 2631 sadb_replay_delete(assoc); 2632 /* Caller will free phdr_mp and return NULL. */ 2633 return (B_FALSE); 2634 } 2635 2636 if (ah_data_sz != ah_align_sz) { 2637 uchar_t *pad = ((uchar_t *)phdr_ah + sizeof (ah_t) + 2638 ah_data_sz); 2639 2640 for (i = 0; i < (ah_align_sz - ah_data_sz); i++) { 2641 pad[i] = (uchar_t)i; /* Fill the padding */ 2642 } 2643 } 2644 } else { 2645 /* Inbound AH datagram. */ 2646 phdr_ah->ah_nexthdr = inbound_ah->ah_nexthdr; 2647 phdr_ah->ah_length = inbound_ah->ah_length; 2648 phdr_ah->ah_reserved = 0; 2649 ASSERT(inbound_ah->ah_spi == assoc->ipsa_spi); 2650 phdr_ah->ah_spi = inbound_ah->ah_spi; 2651 phdr_ah->ah_replay = inbound_ah->ah_replay; 2652 2653 if (ah_data_sz != ah_align_sz) { 2654 uchar_t *opad = ((uchar_t *)inbound_ah + sizeof (ah_t) + 2655 ah_data_sz); 2656 uchar_t *pad = ((uchar_t *)phdr_ah + sizeof (ah_t) + 2657 ah_data_sz); 2658 2659 for (i = 0; i < (ah_align_sz - ah_data_sz); i++) { 2660 pad[i] = opad[i]; /* Copy the padding */ 2661 } 2662 } 2663 } 2664 2665 return (B_TRUE); 2666 } 2667 2668 /* 2669 * Called upon failing the inbound ICV check. The message passed as 2670 * argument is freed. 2671 */ 2672 static void 2673 ah_log_bad_auth(mblk_t *ipsec_in) 2674 { 2675 mblk_t *mp = ipsec_in->b_cont->b_cont; 2676 ipsec_in_t *ii = (ipsec_in_t *)ipsec_in->b_rptr; 2677 boolean_t isv4 = ii->ipsec_in_v4; 2678 ipsa_t *assoc = ii->ipsec_in_ah_sa; 2679 int af; 2680 void *addr; 2681 2682 mp->b_rptr -= ii->ipsec_in_skip_len; 2683 2684 if (isv4) { 2685 ipha_t *ipha = (ipha_t *)mp->b_rptr; 2686 addr = &ipha->ipha_dst; 2687 af = AF_INET; 2688 } else { 2689 ip6_t *ip6h = (ip6_t *)mp->b_rptr; 2690 addr = &ip6h->ip6_dst; 2691 af = AF_INET6; 2692 } 2693 2694 /* 2695 * Log the event. Don't print to the console, block 2696 * potential denial-of-service attack. 2697 */ 2698 AH_BUMP_STAT(bad_auth); 2699 2700 ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 2701 "AH Authentication failed spi %x, dst_addr %s", 2702 assoc->ipsa_spi, addr, af); 2703 2704 IP_AH_BUMP_STAT(in_discards); 2705 ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, &ipdrops_ah_bad_auth, 2706 &ah_dropper); 2707 } 2708 2709 /* 2710 * Kernel crypto framework callback invoked after completion of async 2711 * crypto requests. 2712 */ 2713 static void 2714 ah_kcf_callback(void *arg, int status) 2715 { 2716 mblk_t *ipsec_mp = (mblk_t *)arg; 2717 ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr; 2718 boolean_t is_inbound = (ii->ipsec_in_type == IPSEC_IN); 2719 2720 ASSERT(ipsec_mp->b_cont != NULL); 2721 2722 if (status == CRYPTO_SUCCESS) { 2723 if (is_inbound) { 2724 if (ah_auth_in_done(ipsec_mp) != IPSEC_STATUS_SUCCESS) 2725 return; 2726 /* finish IPsec processing */ 2727 ip_fanout_proto_again(ipsec_mp, NULL, NULL, NULL); 2728 } else { 2729 ipha_t *ipha; 2730 2731 if (ah_auth_out_done(ipsec_mp) != IPSEC_STATUS_SUCCESS) 2732 return; 2733 2734 /* finish IPsec processing */ 2735 ipha = (ipha_t *)ipsec_mp->b_cont->b_rptr; 2736 if (IPH_HDR_VERSION(ipha) == IP_VERSION) { 2737 ip_wput_ipsec_out(NULL, ipsec_mp, ipha, NULL, 2738 NULL); 2739 } else { 2740 ip6_t *ip6h = (ip6_t *)ipha; 2741 ip_wput_ipsec_out_v6(NULL, ipsec_mp, ip6h, 2742 NULL, NULL); 2743 } 2744 } 2745 2746 } else if (status == CRYPTO_INVALID_MAC) { 2747 ah_log_bad_auth(ipsec_mp); 2748 2749 } else { 2750 ah1dbg(("ah_kcf_callback: crypto failed with 0x%x\n", status)); 2751 AH_BUMP_STAT(crypto_failures); 2752 if (is_inbound) 2753 IP_AH_BUMP_STAT(in_discards); 2754 else 2755 AH_BUMP_STAT(out_discards); 2756 ip_drop_packet(ipsec_mp, is_inbound, NULL, NULL, 2757 &ipdrops_ah_crypto_failed, &ah_dropper); 2758 } 2759 } 2760 2761 /* 2762 * Invoked on kernel crypto failure during inbound and outbound processing. 2763 */ 2764 static void 2765 ah_crypto_failed(mblk_t *mp, boolean_t is_inbound, int kef_rc) 2766 { 2767 ah1dbg(("crypto failed for %s AH with 0x%x\n", 2768 is_inbound ? "inbound" : "outbound", kef_rc)); 2769 ip_drop_packet(mp, is_inbound, NULL, NULL, &ipdrops_ah_crypto_failed, 2770 &ah_dropper); 2771 AH_BUMP_STAT(crypto_failures); 2772 if (is_inbound) 2773 IP_AH_BUMP_STAT(in_discards); 2774 else 2775 AH_BUMP_STAT(out_discards); 2776 } 2777 2778 /* 2779 * Helper macros for the ah_submit_req_{inbound,outbound}() functions. 2780 */ 2781 2782 #define AH_INIT_CALLREQ(_cr) { \ 2783 (_cr)->cr_flag = CRYPTO_SKIP_REQID|CRYPTO_RESTRICTED; \ 2784 if (ipsec_algs_exec_mode[IPSEC_ALG_AUTH] == IPSEC_ALGS_EXEC_ASYNC) \ 2785 (_cr)->cr_flag |= CRYPTO_ALWAYS_QUEUE; \ 2786 (_cr)->cr_callback_arg = ipsec_mp; \ 2787 (_cr)->cr_callback_func = ah_kcf_callback; \ 2788 } 2789 2790 #define AH_INIT_CRYPTO_DATA(data, msglen, mblk) { \ 2791 (data)->cd_format = CRYPTO_DATA_MBLK; \ 2792 (data)->cd_mp = mblk; \ 2793 (data)->cd_offset = 0; \ 2794 (data)->cd_length = msglen; \ 2795 } 2796 2797 #define AH_INIT_CRYPTO_MAC(mac, icvlen, icvbuf) { \ 2798 (mac)->cd_format = CRYPTO_DATA_RAW; \ 2799 (mac)->cd_offset = 0; \ 2800 (mac)->cd_length = icvlen; \ 2801 (mac)->cd_raw.iov_base = icvbuf; \ 2802 (mac)->cd_raw.iov_len = icvlen; \ 2803 } 2804 2805 /* 2806 * Submit an inbound packet for processing by the crypto framework. 2807 */ 2808 static ipsec_status_t 2809 ah_submit_req_inbound(mblk_t *ipsec_mp, size_t skip_len, uint32_t ah_offset, 2810 ipsa_t *assoc) 2811 { 2812 int kef_rc; 2813 mblk_t *phdr_mp; 2814 crypto_call_req_t call_req; 2815 ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr; 2816 uint_t icv_len = assoc->ipsa_mac_len; 2817 crypto_ctx_template_t ctx_tmpl; 2818 2819 phdr_mp = ipsec_mp->b_cont; 2820 ASSERT(phdr_mp != NULL); 2821 ASSERT(ii->ipsec_in_type == IPSEC_IN); 2822 2823 /* init arguments for the crypto framework */ 2824 AH_INIT_CRYPTO_DATA(&ii->ipsec_in_crypto_data, AH_MSGSIZE(phdr_mp), 2825 phdr_mp); 2826 2827 AH_INIT_CRYPTO_MAC(&ii->ipsec_in_crypto_mac, icv_len, 2828 (char *)phdr_mp->b_cont->b_rptr - skip_len + ah_offset + 2829 sizeof (ah_t)); 2830 2831 AH_INIT_CALLREQ(&call_req); 2832 2833 ii->ipsec_in_skip_len = skip_len; 2834 2835 IPSEC_CTX_TMPL(assoc, ipsa_authtmpl, IPSEC_ALG_AUTH, ctx_tmpl); 2836 2837 /* call KEF to do the MAC operation */ 2838 kef_rc = crypto_mac_verify(&assoc->ipsa_amech, 2839 &ii->ipsec_in_crypto_data, &assoc->ipsa_kcfauthkey, ctx_tmpl, 2840 &ii->ipsec_in_crypto_mac, &call_req); 2841 2842 switch (kef_rc) { 2843 case CRYPTO_SUCCESS: 2844 AH_BUMP_STAT(crypto_sync); 2845 return (ah_auth_in_done(ipsec_mp)); 2846 case CRYPTO_QUEUED: 2847 /* ah_callback() will be invoked on completion */ 2848 AH_BUMP_STAT(crypto_async); 2849 return (IPSEC_STATUS_PENDING); 2850 case CRYPTO_INVALID_MAC: 2851 AH_BUMP_STAT(crypto_sync); 2852 ah_log_bad_auth(ipsec_mp); 2853 return (IPSEC_STATUS_FAILED); 2854 } 2855 2856 ah_crypto_failed(ipsec_mp, B_TRUE, kef_rc); 2857 return (IPSEC_STATUS_FAILED); 2858 } 2859 2860 /* 2861 * Submit an outbound packet for processing by the crypto framework. 2862 */ 2863 static ipsec_status_t 2864 ah_submit_req_outbound(mblk_t *ipsec_mp, size_t skip_len, ipsa_t *assoc) 2865 { 2866 int kef_rc; 2867 mblk_t *phdr_mp; 2868 crypto_call_req_t call_req; 2869 ipsec_out_t *io = (ipsec_out_t *)ipsec_mp->b_rptr; 2870 uint_t icv_len = assoc->ipsa_mac_len; 2871 2872 phdr_mp = ipsec_mp->b_cont; 2873 ASSERT(phdr_mp != NULL); 2874 ASSERT(io->ipsec_out_type == IPSEC_OUT); 2875 2876 /* init arguments for the crypto framework */ 2877 AH_INIT_CRYPTO_DATA(&io->ipsec_out_crypto_data, AH_MSGSIZE(phdr_mp), 2878 phdr_mp); 2879 2880 AH_INIT_CRYPTO_MAC(&io->ipsec_out_crypto_mac, icv_len, 2881 (char *)phdr_mp->b_wptr); 2882 2883 AH_INIT_CALLREQ(&call_req); 2884 2885 io->ipsec_out_skip_len = skip_len; 2886 2887 ASSERT(io->ipsec_out_ah_sa != NULL); 2888 2889 /* call KEF to do the MAC operation */ 2890 kef_rc = crypto_mac(&assoc->ipsa_amech, &io->ipsec_out_crypto_data, 2891 &assoc->ipsa_kcfauthkey, assoc->ipsa_authtmpl, 2892 &io->ipsec_out_crypto_mac, &call_req); 2893 2894 switch (kef_rc) { 2895 case CRYPTO_SUCCESS: 2896 AH_BUMP_STAT(crypto_sync); 2897 return (ah_auth_out_done(ipsec_mp)); 2898 case CRYPTO_QUEUED: 2899 /* ah_callback() will be invoked on completion */ 2900 AH_BUMP_STAT(crypto_async); 2901 return (IPSEC_STATUS_PENDING); 2902 } 2903 2904 ah_crypto_failed(ipsec_mp, B_FALSE, kef_rc); 2905 return (IPSEC_STATUS_FAILED); 2906 } 2907 2908 /* 2909 * This function constructs a pseudo header by looking at the IP header 2910 * and options if any. This is called for both outbound and inbound, 2911 * before computing the ICV. 2912 */ 2913 static mblk_t * 2914 ah_process_ip_options_v6(mblk_t *mp, ipsa_t *assoc, int *length_to_skip, 2915 uint_t ah_data_sz, boolean_t outbound) 2916 { 2917 ip6_t *ip6h; 2918 ip6_t *oip6h; 2919 mblk_t *phdr_mp; 2920 int option_length; 2921 uint_t ah_align_sz; 2922 uint_t ah_offset; 2923 int hdr_size; 2924 2925 /* 2926 * Allocate space for the authentication data also. It is 2927 * useful both during the ICV calculation where we need to 2928 * feed in zeroes and while sending the datagram back to IP 2929 * where we will be using the same space. 2930 * 2931 * We need to allocate space for padding bytes if it is not 2932 * a multiple of IPV6_PADDING_ALIGN. 2933 * 2934 * In addition, we allocate space for the ICV computed by 2935 * the kernel crypto framework, saving us a separate kmem 2936 * allocation down the road. 2937 */ 2938 2939 ah_align_sz = P2ALIGN(ah_data_sz + IPV6_PADDING_ALIGN - 1, 2940 IPV6_PADDING_ALIGN); 2941 2942 ASSERT(ah_align_sz >= ah_data_sz); 2943 2944 hdr_size = ipsec_ah_get_hdr_size_v6(mp, B_FALSE); 2945 option_length = hdr_size - IPV6_HDR_LEN; 2946 2947 /* This was not included in ipsec_ah_get_hdr_size_v6() */ 2948 hdr_size += (sizeof (ah_t) + ah_align_sz); 2949 2950 if (!outbound && (MBLKL(mp) < hdr_size)) { 2951 /* 2952 * We have post-AH header options in a separate mblk, 2953 * a pullup is required. 2954 */ 2955 if (!pullupmsg(mp, hdr_size)) 2956 return (NULL); 2957 } 2958 2959 if ((phdr_mp = allocb(hdr_size + ah_data_sz, BPRI_HI)) == NULL) { 2960 return (NULL); 2961 } 2962 2963 oip6h = (ip6_t *)mp->b_rptr; 2964 2965 /* 2966 * Form the basic IP header first. Zero out the header 2967 * so that the mutable fields are zeroed out. 2968 */ 2969 ip6h = (ip6_t *)phdr_mp->b_rptr; 2970 bzero(ip6h, sizeof (ip6_t)); 2971 ip6h->ip6_vcf = IPV6_DEFAULT_VERS_AND_FLOW; 2972 2973 if (outbound) { 2974 /* 2975 * Include the size of AH and authentication data. 2976 * This is how our recipient would compute the 2977 * authentication data. Look at what we do in the 2978 * inbound case below. 2979 */ 2980 ip6h->ip6_plen = htons(ntohs(oip6h->ip6_plen) + 2981 sizeof (ah_t) + ah_align_sz); 2982 } else { 2983 ip6h->ip6_plen = oip6h->ip6_plen; 2984 } 2985 2986 ip6h->ip6_src = oip6h->ip6_src; 2987 ip6h->ip6_dst = oip6h->ip6_dst; 2988 2989 *length_to_skip = IPV6_HDR_LEN; 2990 if (option_length == 0) { 2991 /* Form the AH header */ 2992 ip6h->ip6_nxt = IPPROTO_AH; 2993 ((ah_t *)(ip6h + 1))->ah_nexthdr = oip6h->ip6_nxt; 2994 ah_offset = *length_to_skip; 2995 } else { 2996 ip6h->ip6_nxt = oip6h->ip6_nxt; 2997 /* option_length does not include the AH header's size */ 2998 *length_to_skip += option_length; 2999 3000 ah_offset = ah_fix_phdr_v6(ip6h, oip6h, outbound, B_FALSE); 3001 if (ah_offset == 0) { 3002 ip_drop_packet(phdr_mp, !outbound, NULL, NULL, 3003 &ipdrops_ah_bad_v6_hdrs, &ah_dropper); 3004 return (NULL); 3005 } 3006 } 3007 3008 if (!ah_finish_up(((ah_t *)((uint8_t *)ip6h + ah_offset)), 3009 (outbound ? NULL : ((ah_t *)((uint8_t *)oip6h + ah_offset))), 3010 assoc, ah_data_sz, ah_align_sz)) { 3011 freeb(phdr_mp); 3012 /* 3013 * Returning NULL will tell the caller to 3014 * IPSA_REFELE(), free the memory, etc. 3015 */ 3016 return (NULL); 3017 } 3018 3019 phdr_mp->b_wptr = ((uint8_t *)ip6h + ah_offset + sizeof (ah_t) + 3020 ah_align_sz); 3021 if (!outbound) 3022 *length_to_skip += sizeof (ah_t) + ah_align_sz; 3023 return (phdr_mp); 3024 } 3025 3026 /* 3027 * This function constructs a pseudo header by looking at the IP header 3028 * and options if any. This is called for both outbound and inbound, 3029 * before computing the ICV. 3030 */ 3031 static mblk_t * 3032 ah_process_ip_options_v4(mblk_t *mp, ipsa_t *assoc, int *length_to_skip, 3033 uint_t ah_data_sz, boolean_t outbound) 3034 { 3035 ipoptp_t opts; 3036 uint32_t option_length; 3037 ipha_t *ipha; 3038 ipha_t *oipha; 3039 mblk_t *phdr_mp; 3040 int size; 3041 uchar_t *optptr; 3042 uint8_t optval; 3043 uint8_t optlen; 3044 ipaddr_t dst; 3045 uint32_t v_hlen_tos_len; 3046 int ip_hdr_length; 3047 uint_t ah_align_sz; 3048 uint32_t off; 3049 3050 #ifdef _BIG_ENDIAN 3051 #define V_HLEN (v_hlen_tos_len >> 24) 3052 #else 3053 #define V_HLEN (v_hlen_tos_len & 0xFF) 3054 #endif 3055 3056 oipha = (ipha_t *)mp->b_rptr; 3057 v_hlen_tos_len = ((uint32_t *)oipha)[0]; 3058 3059 /* 3060 * Allocate space for the authentication data also. It is 3061 * useful both during the ICV calculation where we need to 3062 * feed in zeroes and while sending the datagram back to IP 3063 * where we will be using the same space. 3064 * 3065 * We need to allocate space for padding bytes if it is not 3066 * a multiple of IPV4_PADDING_ALIGN. 3067 * 3068 * In addition, we allocate space for the ICV computed by 3069 * the kernel crypto framework, saving us a separate kmem 3070 * allocation down the road. 3071 */ 3072 3073 ah_align_sz = P2ALIGN(ah_data_sz + IPV4_PADDING_ALIGN - 1, 3074 IPV4_PADDING_ALIGN); 3075 3076 ASSERT(ah_align_sz >= ah_data_sz); 3077 3078 size = IP_SIMPLE_HDR_LENGTH + sizeof (ah_t) + ah_align_sz + 3079 ah_data_sz; 3080 3081 if (V_HLEN != IP_SIMPLE_HDR_VERSION) { 3082 option_length = oipha->ipha_version_and_hdr_length - 3083 (uint8_t)((IP_VERSION << 4) + 3084 IP_SIMPLE_HDR_LENGTH_IN_WORDS); 3085 option_length <<= 2; 3086 size += option_length; 3087 } 3088 3089 if ((phdr_mp = allocb(size, BPRI_HI)) == NULL) { 3090 return (NULL); 3091 } 3092 3093 /* 3094 * Form the basic IP header first. 3095 */ 3096 ipha = (ipha_t *)phdr_mp->b_rptr; 3097 ipha->ipha_version_and_hdr_length = oipha->ipha_version_and_hdr_length; 3098 ipha->ipha_type_of_service = 0; 3099 3100 if (outbound) { 3101 /* 3102 * Include the size of AH and authentication data. 3103 * This is how our recipient would compute the 3104 * authentication data. Look at what we do in the 3105 * inbound case below. 3106 */ 3107 ipha->ipha_length = ntohs(htons(oipha->ipha_length) + 3108 sizeof (ah_t) + ah_align_sz); 3109 } else { 3110 ipha->ipha_length = oipha->ipha_length; 3111 } 3112 3113 ipha->ipha_ident = oipha->ipha_ident; 3114 ipha->ipha_fragment_offset_and_flags = 0; 3115 ipha->ipha_ttl = 0; 3116 ipha->ipha_protocol = IPPROTO_AH; 3117 ipha->ipha_hdr_checksum = 0; 3118 ipha->ipha_src = oipha->ipha_src; 3119 ipha->ipha_dst = dst = oipha->ipha_dst; 3120 3121 /* 3122 * If there is no option to process return now. 3123 */ 3124 ip_hdr_length = IP_SIMPLE_HDR_LENGTH; 3125 3126 if (V_HLEN == IP_SIMPLE_HDR_VERSION) { 3127 /* Form the AH header */ 3128 goto ah_hdr; 3129 } 3130 3131 ip_hdr_length += option_length; 3132 3133 /* 3134 * We have options. In the outbound case for source route, 3135 * ULP has already moved the first hop, which is now in 3136 * ipha_dst. We need the final destination for the calculation 3137 * of authentication data. And also make sure that mutable 3138 * and experimental fields are zeroed out in the IP options. 3139 */ 3140 3141 bcopy(&oipha[1], &ipha[1], option_length); 3142 3143 for (optval = ipoptp_first(&opts, ipha); 3144 optval != IPOPT_EOL; 3145 optval = ipoptp_next(&opts)) { 3146 optptr = opts.ipoptp_cur; 3147 optlen = opts.ipoptp_len; 3148 switch (optval) { 3149 case IPOPT_EXTSEC: 3150 case IPOPT_COMSEC: 3151 case IPOPT_RA: 3152 case IPOPT_SDMDD: 3153 case IPOPT_SECURITY: 3154 /* 3155 * These options are Immutable, leave them as-is. 3156 * Note that IPOPT_NOP is also Immutable, but it 3157 * was skipped by ipoptp_next() and thus remains 3158 * intact in the header. 3159 */ 3160 break; 3161 case IPOPT_SSRR: 3162 case IPOPT_LSRR: 3163 if ((opts.ipoptp_flags & IPOPTP_ERROR) != 0) 3164 goto bad_ipv4opt; 3165 /* 3166 * These two are mutable and will be zeroed, but 3167 * first get the final destination. 3168 */ 3169 off = optptr[IPOPT_OFFSET]; 3170 /* 3171 * If one of the conditions is true, it means 3172 * end of options and dst already has the right 3173 * value. So, just fall through. 3174 */ 3175 if (!(optlen < IP_ADDR_LEN || off > optlen - 3)) { 3176 off = optlen - IP_ADDR_LEN; 3177 bcopy(&optptr[off], &dst, IP_ADDR_LEN); 3178 } 3179 /* FALLTHRU */ 3180 case IPOPT_RR: 3181 case IPOPT_TS: 3182 case IPOPT_SATID: 3183 default: 3184 /* 3185 * optlen should include from the beginning of an 3186 * option. 3187 * NOTE : Stream Identifier Option (SID): RFC 791 3188 * shows the bit pattern of optlen as 2 and documents 3189 * the length as 4. We assume it to be 2 here. 3190 */ 3191 bzero(optptr, optlen); 3192 break; 3193 } 3194 } 3195 3196 if ((opts.ipoptp_flags & IPOPTP_ERROR) != 0) { 3197 bad_ipv4opt: 3198 ah1dbg(("AH : bad IPv4 option")); 3199 freeb(phdr_mp); 3200 return (NULL); 3201 } 3202 3203 /* 3204 * Don't change ipha_dst for an inbound datagram as it points 3205 * to the right value. Only for the outbound with LSRR/SSRR, 3206 * because of ip_massage_options called by the ULP, ipha_dst 3207 * points to the first hop and we need to use the final 3208 * destination for computing the ICV. 3209 */ 3210 3211 if (outbound) 3212 ipha->ipha_dst = dst; 3213 ah_hdr: 3214 ((ah_t *)((uint8_t *)ipha + ip_hdr_length))->ah_nexthdr = 3215 oipha->ipha_protocol; 3216 if (!ah_finish_up(((ah_t *)((uint8_t *)ipha + ip_hdr_length)), 3217 (outbound ? NULL : ((ah_t *)((uint8_t *)oipha + ip_hdr_length))), 3218 assoc, ah_data_sz, ah_align_sz)) { 3219 freeb(phdr_mp); 3220 /* 3221 * Returning NULL will tell the caller to IPSA_REFELE(), free 3222 * the memory, etc. 3223 */ 3224 return (NULL); 3225 } 3226 3227 phdr_mp->b_wptr = ((uchar_t *)ipha + ip_hdr_length + 3228 sizeof (ah_t) + ah_align_sz); 3229 3230 ASSERT(phdr_mp->b_wptr <= phdr_mp->b_datap->db_lim); 3231 if (outbound) 3232 *length_to_skip = ip_hdr_length; 3233 else 3234 *length_to_skip = ip_hdr_length + sizeof (ah_t) + ah_align_sz; 3235 return (phdr_mp); 3236 } 3237 3238 /* 3239 * Authenticate an outbound datagram. This function is called 3240 * whenever IP sends an outbound datagram that needs authentication. 3241 */ 3242 static ipsec_status_t 3243 ah_outbound(mblk_t *ipsec_out) 3244 { 3245 mblk_t *mp; 3246 mblk_t *phdr_mp; 3247 ipsec_out_t *oi; 3248 ipsa_t *assoc; 3249 int length_to_skip; 3250 uint_t ah_align_sz; 3251 uint_t age_bytes; 3252 3253 /* 3254 * Construct the chain of mblks 3255 * 3256 * IPSEC_OUT->PSEUDO_HDR->DATA 3257 * 3258 * one by one. 3259 */ 3260 3261 AH_BUMP_STAT(out_requests); 3262 3263 ASSERT(ipsec_out->b_datap->db_type == M_CTL); 3264 3265 ASSERT(MBLKL(ipsec_out) >= sizeof (ipsec_info_t)); 3266 3267 mp = ipsec_out->b_cont; 3268 oi = (ipsec_out_t *)ipsec_out->b_rptr; 3269 3270 ASSERT(mp->b_datap->db_type == M_DATA); 3271 3272 assoc = oi->ipsec_out_ah_sa; 3273 ASSERT(assoc != NULL); 3274 if (assoc->ipsa_usetime == 0) 3275 ah_set_usetime(assoc, B_FALSE); 3276 3277 /* 3278 * Age SA according to number of bytes that will be sent after 3279 * adding the AH header, ICV, and padding to the packet. 3280 */ 3281 3282 if (oi->ipsec_out_v4) { 3283 ipha_t *ipha = (ipha_t *)mp->b_rptr; 3284 ah_align_sz = P2ALIGN(assoc->ipsa_mac_len + 3285 IPV4_PADDING_ALIGN - 1, IPV4_PADDING_ALIGN); 3286 age_bytes = ntohs(ipha->ipha_length) + sizeof (ah_t) + 3287 ah_align_sz; 3288 } else { 3289 ip6_t *ip6h = (ip6_t *)mp->b_rptr; 3290 ah_align_sz = P2ALIGN(assoc->ipsa_mac_len + 3291 IPV6_PADDING_ALIGN - 1, IPV6_PADDING_ALIGN); 3292 age_bytes = sizeof (ip6_t) + ntohs(ip6h->ip6_plen) + 3293 sizeof (ah_t) + ah_align_sz; 3294 } 3295 3296 if (!ah_age_bytes(assoc, age_bytes, B_FALSE)) { 3297 /* rig things as if ipsec_getassocbyconn() failed */ 3298 ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 3299 "AH association 0x%x, dst %s had bytes expire.\n", 3300 ntohl(assoc->ipsa_spi), assoc->ipsa_dstaddr, AF_INET); 3301 freemsg(ipsec_out); 3302 return (IPSEC_STATUS_FAILED); 3303 } 3304 3305 if (oi->ipsec_out_is_capab_ill) { 3306 ah3dbg(("ah_outbound: pkt can be accelerated\n")); 3307 if (oi->ipsec_out_v4) 3308 return (ah_outbound_accelerated_v4(ipsec_out, assoc)); 3309 else 3310 return (ah_outbound_accelerated_v6(ipsec_out, assoc)); 3311 } 3312 AH_BUMP_STAT(noaccel); 3313 3314 /* 3315 * Insert pseudo header: 3316 * IPSEC_INFO -> [IP, ULP] => IPSEC_INFO -> [IP, AH, ICV] -> ULP 3317 */ 3318 3319 if (oi->ipsec_out_v4) { 3320 phdr_mp = ah_process_ip_options_v4(mp, assoc, &length_to_skip, 3321 assoc->ipsa_mac_len, B_TRUE); 3322 } else { 3323 phdr_mp = ah_process_ip_options_v6(mp, assoc, &length_to_skip, 3324 assoc->ipsa_mac_len, B_TRUE); 3325 } 3326 3327 if (phdr_mp == NULL) { 3328 AH_BUMP_STAT(out_discards); 3329 ip_drop_packet(ipsec_out, B_FALSE, NULL, NULL, 3330 &ipdrops_ah_bad_v4_opts, &ah_dropper); 3331 return (IPSEC_STATUS_FAILED); 3332 } 3333 3334 ipsec_out->b_cont = phdr_mp; 3335 phdr_mp->b_cont = mp; 3336 mp->b_rptr += length_to_skip; 3337 3338 /* 3339 * At this point ipsec_out points to the IPSEC_OUT, new_mp 3340 * points to an mblk containing the pseudo header (IP header, 3341 * AH header, and ICV with mutable fields zero'ed out). 3342 * mp points to the mblk containing the ULP data. The original 3343 * IP header is kept before the ULP data in mp. 3344 */ 3345 3346 /* submit MAC request to KCF */ 3347 return (ah_submit_req_outbound(ipsec_out, length_to_skip, assoc)); 3348 } 3349 3350 static ipsec_status_t 3351 ah_inbound(mblk_t *ipsec_in_mp, void *arg) 3352 { 3353 mblk_t *data_mp = ipsec_in_mp->b_cont; 3354 ipsec_in_t *ii = (ipsec_in_t *)ipsec_in_mp->b_rptr; 3355 ah_t *ah = (ah_t *)arg; 3356 ipsa_t *assoc = ii->ipsec_in_ah_sa; 3357 int length_to_skip; 3358 int ah_length; 3359 mblk_t *phdr_mp; 3360 uint32_t ah_offset; 3361 3362 ASSERT(assoc != NULL); 3363 if (assoc->ipsa_usetime == 0) 3364 ah_set_usetime(assoc, B_TRUE); 3365 3366 /* 3367 * We may wish to check replay in-range-only here as an optimization. 3368 * Include the reality check of ipsa->ipsa_replay > 3369 * ipsa->ipsa_replay_wsize for times when it's the first N packets, 3370 * where N == ipsa->ipsa_replay_wsize. 3371 * 3372 * Another check that may come here later is the "collision" check. 3373 * If legitimate packets flow quickly enough, this won't be a problem, 3374 * but collisions may cause authentication algorithm crunching to 3375 * take place when it doesn't need to. 3376 */ 3377 if (!sadb_replay_peek(assoc, ah->ah_replay)) { 3378 AH_BUMP_STAT(replay_early_failures); 3379 IP_AH_BUMP_STAT(in_discards); 3380 ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL, 3381 &ipdrops_ah_early_replay, &ah_dropper); 3382 return (IPSEC_STATUS_FAILED); 3383 } 3384 3385 /* 3386 * The offset of the AH header can be computed from its pointer 3387 * within the data mblk, which was pulled up until the AH header 3388 * by ipsec_inbound_ah_sa() during SA selection. 3389 */ 3390 ah_offset = (uchar_t *)ah - data_mp->b_rptr; 3391 3392 /* 3393 * Has this packet already been processed by a hardware 3394 * IPsec accelerator? 3395 */ 3396 if (ii->ipsec_in_accelerated) { 3397 ah3dbg(("ah_inbound_v6: pkt processed by ill=%d isv6=%d\n", 3398 ii->ipsec_in_ill_index, !ii->ipsec_in_v4)); 3399 return (ah_inbound_accelerated(ipsec_in_mp, ii->ipsec_in_v4, 3400 assoc, ah_offset)); 3401 } 3402 AH_BUMP_STAT(noaccel); 3403 3404 /* 3405 * We need to pullup until the ICV before we call 3406 * ah_process_ip_options_v6. 3407 */ 3408 ah_length = (ah->ah_length << 2) + 8; 3409 3410 /* 3411 * NOTE : If we want to use any field of IP/AH header, you need 3412 * to re-assign following the pullup. 3413 */ 3414 if (((uchar_t *)ah + ah_length) > data_mp->b_wptr) { 3415 if (!pullupmsg(data_mp, (uchar_t *)ah + ah_length - 3416 data_mp->b_rptr)) { 3417 (void) ipsec_rl_strlog(info.mi_idnum, 0, 0, 3418 SL_WARN | SL_ERROR, 3419 "ah_inbound: Small AH header\n"); 3420 IP_AH_BUMP_STAT(in_discards); 3421 ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL, 3422 &ipdrops_ah_nomem, &ah_dropper); 3423 return (IPSEC_STATUS_FAILED); 3424 } 3425 } 3426 3427 /* 3428 * Insert pseudo header: 3429 * IPSEC_INFO -> [IP, ULP] => IPSEC_INFO -> [IP, AH, ICV] -> ULP 3430 */ 3431 if (ii->ipsec_in_v4) { 3432 phdr_mp = ah_process_ip_options_v4(data_mp, assoc, 3433 &length_to_skip, assoc->ipsa_mac_len, B_FALSE); 3434 } else { 3435 phdr_mp = ah_process_ip_options_v6(data_mp, assoc, 3436 &length_to_skip, assoc->ipsa_mac_len, B_FALSE); 3437 } 3438 3439 if (phdr_mp == NULL) { 3440 IP_AH_BUMP_STAT(in_discards); 3441 ip_drop_packet(ipsec_in_mp, B_TRUE, NULL, NULL, 3442 ii->ipsec_in_v4 ? &ipdrops_ah_bad_v4_opts : 3443 &ipdrops_ah_bad_v6_hdrs, &ah_dropper); 3444 return (IPSEC_STATUS_FAILED); 3445 } 3446 3447 ipsec_in_mp->b_cont = phdr_mp; 3448 phdr_mp->b_cont = data_mp; 3449 data_mp->b_rptr += length_to_skip; 3450 3451 /* submit request to KCF */ 3452 return (ah_submit_req_inbound(ipsec_in_mp, length_to_skip, ah_offset, 3453 assoc)); 3454 } 3455 3456 /* 3457 * ah_inbound_accelerated: 3458 * Called from ah_inbound() to process IPsec packets that have been 3459 * accelerated by hardware. 3460 * 3461 * Basically does what ah_auth_in_done() with some changes since 3462 * no pseudo-headers are involved, i.e. the passed message is a 3463 * IPSEC_INFO->DATA. 3464 * 3465 * It is assumed that only packets that have been successfully 3466 * processed by the adapter come here. 3467 * 3468 * 1. get algorithm structure corresponding to association 3469 * 2. calculate pointers to authentication header and ICV 3470 * 3. compare ICV in AH header with ICV in data attributes 3471 * 3.1 if different: 3472 * 3.1.1 generate error 3473 * 3.1.2 discard message 3474 * 3.2 if ICV matches: 3475 * 3.2.1 check replay 3476 * 3.2.2 remove AH header 3477 * 3.2.3 age SA byte 3478 * 3.2.4 send to IP 3479 */ 3480 ipsec_status_t 3481 ah_inbound_accelerated(mblk_t *ipsec_in, boolean_t isv4, ipsa_t *assoc, 3482 uint32_t ah_offset) 3483 { 3484 mblk_t *mp; 3485 ipha_t *ipha; 3486 ah_t *ah; 3487 ipsec_in_t *ii; 3488 uint32_t icv_len; 3489 uint32_t align_len; 3490 uint32_t age_bytes; 3491 ip6_t *ip6h; 3492 uint8_t *in_icv; 3493 mblk_t *hada_mp; 3494 uint32_t next_hdr; 3495 da_ipsec_t *hada; 3496 kstat_named_t *counter; 3497 3498 AH_BUMP_STAT(in_accelerated); 3499 3500 ii = (ipsec_in_t *)ipsec_in->b_rptr; 3501 mp = ipsec_in->b_cont; 3502 hada_mp = ii->ipsec_in_da; 3503 ASSERT(hada_mp != NULL); 3504 hada = (da_ipsec_t *)hada_mp->b_rptr; 3505 3506 /* 3507 * We only support one level of decapsulation in hardware, so 3508 * nuke the pointer. 3509 */ 3510 ii->ipsec_in_da = NULL; 3511 ii->ipsec_in_accelerated = B_FALSE; 3512 3513 /* 3514 * Extract ICV length from attributes M_CTL and sanity check 3515 * its value. We allow the mblk to be smaller than da_ipsec_t 3516 * for a small ICV, as long as the entire ICV fits within the mblk. 3517 * Also ensures that the ICV length computed by Provider 3518 * corresponds to the ICV length of the algorithm specified by the SA. 3519 */ 3520 icv_len = hada->da_icv_len; 3521 if ((icv_len != assoc->ipsa_mac_len) || 3522 (icv_len > DA_ICV_MAX_LEN) || (MBLKL(hada_mp) < 3523 (sizeof (da_ipsec_t) - DA_ICV_MAX_LEN + icv_len))) { 3524 ah0dbg(("ah_inbound_accelerated: " 3525 "ICV len (%u) incorrect or mblk too small (%u)\n", 3526 icv_len, (uint32_t)(MBLKL(hada_mp)))); 3527 counter = &ipdrops_ah_bad_length; 3528 goto ah_in_discard; 3529 } 3530 ASSERT(icv_len != 0); 3531 3532 /* compute the padded AH ICV len */ 3533 if (isv4) { 3534 ipha = (ipha_t *)mp->b_rptr; 3535 align_len = (icv_len + IPV4_PADDING_ALIGN - 1) & 3536 -IPV4_PADDING_ALIGN; 3537 } else { 3538 ip6h = (ip6_t *)mp->b_rptr; 3539 align_len = (icv_len + IPV6_PADDING_ALIGN - 1) & 3540 -IPV6_PADDING_ALIGN; 3541 } 3542 3543 ah = (ah_t *)(mp->b_rptr + ah_offset); 3544 in_icv = (uint8_t *)ah + sizeof (ah_t); 3545 3546 /* compare ICV in AH header vs ICV computed by adapter */ 3547 if (bcmp(hada->da_icv, in_icv, icv_len)) { 3548 int af; 3549 void *addr; 3550 3551 if (isv4) { 3552 addr = &ipha->ipha_dst; 3553 af = AF_INET; 3554 } else { 3555 addr = &ip6h->ip6_dst; 3556 af = AF_INET6; 3557 } 3558 3559 /* 3560 * Log the event. Don't print to the console, block 3561 * potential denial-of-service attack. 3562 */ 3563 AH_BUMP_STAT(bad_auth); 3564 ipsec_assocfailure(info.mi_idnum, 0, 0, SL_ERROR | SL_WARN, 3565 "AH Authentication failed spi %x, dst_addr %s", 3566 assoc->ipsa_spi, addr, af); 3567 counter = &ipdrops_ah_bad_auth; 3568 goto ah_in_discard; 3569 } 3570 3571 ah3dbg(("AH succeeded, checking replay\n")); 3572 AH_BUMP_STAT(good_auth); 3573 3574 if (!sadb_replay_check(assoc, ah->ah_replay)) { 3575 int af; 3576 void *addr; 3577 3578 if (isv4) { 3579 addr = &ipha->ipha_dst; 3580 af = AF_INET; 3581 } else { 3582 addr = &ip6h->ip6_dst; 3583 af = AF_INET6; 3584 } 3585 3586 /* 3587 * Log the event. As of now we print out an event. 3588 * Do not print the replay failure number, or else 3589 * syslog cannot collate the error messages. Printing 3590 * the replay number that failed (or printing to the 3591 * console) opens a denial-of-service attack. 3592 */ 3593 AH_BUMP_STAT(replay_failures); 3594 ipsec_assocfailure(info.mi_idnum, 0, 0, 3595 SL_ERROR | SL_WARN, 3596 "Replay failed for AH spi %x, dst_addr %s", 3597 assoc->ipsa_spi, addr, af); 3598 counter = &ipdrops_ah_replay; 3599 goto ah_in_discard; 3600 } 3601 3602 /* 3603 * Remove AH header. We do this by copying everything before 3604 * the AH header onto the AH header+ICV. 3605 */ 3606 /* overwrite AH with what was preceeding it (IP header) */ 3607 next_hdr = ah->ah_nexthdr; 3608 ovbcopy(mp->b_rptr, mp->b_rptr + sizeof (ah_t) + align_len, 3609 ah_offset); 3610 mp->b_rptr += sizeof (ah_t) + align_len; 3611 if (isv4) { 3612 /* adjust IP header next protocol */ 3613 ipha = (ipha_t *)mp->b_rptr; 3614 ipha->ipha_protocol = next_hdr; 3615 3616 age_bytes = ipha->ipha_length; 3617 3618 /* adjust length in IP header */ 3619 ipha->ipha_length -= (sizeof (ah_t) + align_len); 3620 3621 /* recalculate checksum */ 3622 ipha->ipha_hdr_checksum = 0; 3623 ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha); 3624 } else { 3625 /* adjust IP header next protocol */ 3626 ip6h = (ip6_t *)mp->b_rptr; 3627 ip6h->ip6_nxt = next_hdr; 3628 3629 age_bytes = sizeof (ip6_t) + ntohs(ip6h->ip6_plen) + 3630 sizeof (ah_t); 3631 3632 /* adjust length in IP header */ 3633 ip6h->ip6_plen = htons(ntohs(ip6h->ip6_plen) - 3634 (sizeof (ah_t) + align_len)); 3635 } 3636 3637 /* age SA */ 3638 if (!ah_age_bytes(assoc, age_bytes, B_TRUE)) { 3639 /* The ipsa has hit hard expiration, LOG and AUDIT. */ 3640 ipsec_assocfailure(info.mi_idnum, 0, 0, 3641 SL_ERROR | SL_WARN, 3642 "AH Association 0x%x, dst %s had bytes expire.\n", 3643 assoc->ipsa_spi, assoc->ipsa_dstaddr, 3644 AF_INET); 3645 AH_BUMP_STAT(bytes_expired); 3646 counter = &ipdrops_ah_bytes_expire; 3647 goto ah_in_discard; 3648 } 3649 3650 freeb(hada_mp); 3651 return (IPSEC_STATUS_SUCCESS); 3652 3653 ah_in_discard: 3654 IP_AH_BUMP_STAT(in_discards); 3655 freeb(hada_mp); 3656 ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, counter, &ah_dropper); 3657 return (IPSEC_STATUS_FAILED); 3658 } 3659 3660 /* 3661 * ah_outbound_accelerated_v4: 3662 * Called from ah_outbound_v4() and once it is determined that the 3663 * packet is elligible for hardware acceleration. 3664 * 3665 * We proceed as follows: 3666 * 1. allocate and initialize attributes mblk 3667 * 2. mark IPSEC_OUT to indicate that pkt is accelerated 3668 * 3. insert AH header 3669 */ 3670 static ipsec_status_t 3671 ah_outbound_accelerated_v4(mblk_t *ipsec_mp, ipsa_t *assoc) 3672 { 3673 mblk_t *mp, *new_mp; 3674 ipsec_out_t *oi; 3675 uint_t ah_data_sz; /* ICV length, algorithm dependent */ 3676 uint_t ah_align_sz; /* ICV length + padding */ 3677 uint32_t v_hlen_tos_len; /* from original IP header */ 3678 ipha_t *oipha; /* original IP header */ 3679 ipha_t *nipha; /* new IP header */ 3680 uint_t option_length = 0; 3681 uint_t new_hdr_len; /* new header length */ 3682 uint_t iphdr_length; 3683 ah_t *ah_hdr; /* ptr to AH header */ 3684 3685 AH_BUMP_STAT(out_accelerated); 3686 3687 oi = (ipsec_out_t *)ipsec_mp->b_rptr; 3688 mp = ipsec_mp->b_cont; 3689 3690 oipha = (ipha_t *)mp->b_rptr; 3691 v_hlen_tos_len = ((uint32_t *)oipha)[0]; 3692 3693 /* mark packet as being accelerated in IPSEC_OUT */ 3694 ASSERT(oi->ipsec_out_accelerated == B_FALSE); 3695 oi->ipsec_out_accelerated = B_TRUE; 3696 3697 /* calculate authentication data length, i.e. ICV + padding */ 3698 ah_data_sz = assoc->ipsa_mac_len; 3699 ah_align_sz = (ah_data_sz + IPV4_PADDING_ALIGN - 1) & 3700 -IPV4_PADDING_ALIGN; 3701 3702 /* 3703 * Insert pseudo header: 3704 * IPSEC_INFO -> [IP, ULP] => IPSEC_INFO -> [IP, AH, ICV] -> ULP 3705 */ 3706 3707 /* IP + AH + authentication + padding data length */ 3708 new_hdr_len = IP_SIMPLE_HDR_LENGTH + sizeof (ah_t) + ah_align_sz; 3709 if (V_HLEN != IP_SIMPLE_HDR_VERSION) { 3710 option_length = oipha->ipha_version_and_hdr_length - 3711 (uint8_t)((IP_VERSION << 4) + 3712 IP_SIMPLE_HDR_LENGTH_IN_WORDS); 3713 option_length <<= 2; 3714 new_hdr_len += option_length; 3715 } 3716 3717 /* allocate pseudo-header mblk */ 3718 if ((new_mp = allocb(new_hdr_len, BPRI_HI)) == NULL) { 3719 /* IPsec kstats: bump bean counter here */ 3720 ip_drop_packet(ipsec_mp, B_FALSE, NULL, NULL, 3721 &ipdrops_ah_nomem, &ah_dropper); 3722 return (IPSEC_STATUS_FAILED); 3723 } 3724 3725 new_mp->b_cont = mp; 3726 ipsec_mp->b_cont = new_mp; 3727 new_mp->b_wptr += new_hdr_len; 3728 3729 /* copy original IP header to new header */ 3730 bcopy(mp->b_rptr, new_mp->b_rptr, IP_SIMPLE_HDR_LENGTH + 3731 option_length); 3732 3733 /* update IP header */ 3734 nipha = (ipha_t *)new_mp->b_rptr; 3735 nipha->ipha_protocol = IPPROTO_AH; 3736 iphdr_length = ntohs(nipha->ipha_length); 3737 iphdr_length += sizeof (ah_t) + ah_align_sz; 3738 nipha->ipha_length = htons(iphdr_length); 3739 nipha->ipha_hdr_checksum = 0; 3740 nipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(nipha); 3741 3742 /* skip original IP header in mp */ 3743 mp->b_rptr += IP_SIMPLE_HDR_LENGTH + option_length; 3744 3745 /* initialize AH header */ 3746 ah_hdr = (ah_t *)(new_mp->b_rptr + IP_SIMPLE_HDR_LENGTH + 3747 option_length); 3748 ah_hdr->ah_nexthdr = oipha->ipha_protocol; 3749 if (!ah_finish_up(ah_hdr, NULL, assoc, ah_data_sz, ah_align_sz)) { 3750 /* Only way this fails is if outbound replay counter wraps. */ 3751 ip_drop_packet(ipsec_mp, B_FALSE, NULL, NULL, 3752 &ipdrops_ah_replay, &ah_dropper); 3753 return (IPSEC_STATUS_FAILED); 3754 } 3755 3756 return (IPSEC_STATUS_SUCCESS); 3757 } 3758 3759 /* 3760 * ah_outbound_accelerated_v6: 3761 * 3762 * Called from ah_outbound_v6() once it is determined that the packet 3763 * is eligible for hardware acceleration. 3764 * 3765 * We proceed as follows: 3766 * 1. allocate and initialize attributes mblk 3767 * 2. mark IPSEC_OUT to indicate that pkt is accelerated 3768 * 3. insert AH header 3769 */ 3770 static ipsec_status_t 3771 ah_outbound_accelerated_v6(mblk_t *ipsec_mp, ipsa_t *assoc) 3772 { 3773 mblk_t *mp, *phdr_mp; 3774 ipsec_out_t *oi; 3775 uint_t ah_data_sz; /* ICV length, algorithm dependent */ 3776 uint_t ah_align_sz; /* ICV length + padding */ 3777 ip6_t *oip6h; /* original IP header */ 3778 ip6_t *ip6h; /* new IP header */ 3779 uint_t option_length = 0; 3780 uint_t hdr_size; 3781 uint_t ah_offset; 3782 ah_t *ah_hdr; /* ptr to AH header */ 3783 3784 AH_BUMP_STAT(out_accelerated); 3785 3786 oi = (ipsec_out_t *)ipsec_mp->b_rptr; 3787 mp = ipsec_mp->b_cont; 3788 3789 oip6h = (ip6_t *)mp->b_rptr; 3790 3791 /* mark packet as being accelerated in IPSEC_OUT */ 3792 ASSERT(oi->ipsec_out_accelerated == B_FALSE); 3793 oi->ipsec_out_accelerated = B_TRUE; 3794 3795 /* calculate authentication data length, i.e. ICV + padding */ 3796 ah_data_sz = assoc->ipsa_mac_len; 3797 ah_align_sz = (ah_data_sz + IPV4_PADDING_ALIGN - 1) & 3798 -IPV4_PADDING_ALIGN; 3799 3800 ASSERT(ah_align_sz >= ah_data_sz); 3801 3802 hdr_size = ipsec_ah_get_hdr_size_v6(mp, B_FALSE); 3803 option_length = hdr_size - IPV6_HDR_LEN; 3804 3805 /* This was not included in ipsec_ah_get_hdr_size_v6() */ 3806 hdr_size += (sizeof (ah_t) + ah_align_sz); 3807 3808 if ((phdr_mp = allocb(hdr_size, BPRI_HI)) == NULL) { 3809 ip_drop_packet(ipsec_mp, B_FALSE, NULL, NULL, &ipdrops_ah_nomem, 3810 &ah_dropper); 3811 return (IPSEC_STATUS_FAILED); 3812 } 3813 phdr_mp->b_wptr += hdr_size; 3814 3815 /* 3816 * Form the basic IP header first. We always assign every bit 3817 * of the v6 basic header, so a separate bzero is unneeded. 3818 */ 3819 ip6h = (ip6_t *)phdr_mp->b_rptr; 3820 ip6h->ip6_vcf = oip6h->ip6_vcf; 3821 ip6h->ip6_hlim = oip6h->ip6_hlim; 3822 ip6h->ip6_src = oip6h->ip6_src; 3823 ip6h->ip6_dst = oip6h->ip6_dst; 3824 /* 3825 * Include the size of AH and authentication data. 3826 * This is how our recipient would compute the 3827 * authentication data. Look at what we do in the 3828 * inbound case below. 3829 */ 3830 ip6h->ip6_plen = htons(ntohs(oip6h->ip6_plen) + sizeof (ah_t) + 3831 ah_align_sz); 3832 3833 /* 3834 * Insert pseudo header: 3835 * IPSEC_INFO -> [IP6, LLH, ULP] => 3836 * IPSEC_INFO -> [IP, LLH, AH, ICV] -> ULP 3837 */ 3838 3839 if (option_length == 0) { 3840 /* Form the AH header */ 3841 ip6h->ip6_nxt = IPPROTO_AH; 3842 ((ah_t *)(ip6h + 1))->ah_nexthdr = oip6h->ip6_nxt; 3843 ah_offset = IPV6_HDR_LEN; 3844 } else { 3845 ip6h->ip6_nxt = oip6h->ip6_nxt; 3846 /* option_length does not include the AH header's size */ 3847 ah_offset = ah_fix_phdr_v6(ip6h, oip6h, B_TRUE, B_FALSE); 3848 if (ah_offset == 0) { 3849 freemsg(phdr_mp); 3850 ip_drop_packet(ipsec_mp, B_FALSE, NULL, NULL, 3851 &ipdrops_ah_bad_v6_hdrs, &ah_dropper); 3852 return (IPSEC_STATUS_FAILED); 3853 } 3854 } 3855 3856 phdr_mp->b_cont = mp; 3857 ipsec_mp->b_cont = phdr_mp; 3858 3859 /* skip original IP header in mp */ 3860 mp->b_rptr += IPV6_HDR_LEN + option_length; 3861 3862 /* initialize AH header */ 3863 ah_hdr = (ah_t *)(phdr_mp->b_rptr + IPV6_HDR_LEN + option_length); 3864 ah_hdr->ah_nexthdr = oip6h->ip6_nxt; 3865 3866 if (!ah_finish_up(((ah_t *)((uint8_t *)ip6h + ah_offset)), NULL, 3867 assoc, ah_data_sz, ah_align_sz)) { 3868 /* Only way this fails is if outbound replay counter wraps. */ 3869 ip_drop_packet(ipsec_mp, B_FALSE, NULL, NULL, 3870 &ipdrops_ah_replay, &ah_dropper); 3871 return (IPSEC_STATUS_FAILED); 3872 } 3873 3874 return (IPSEC_STATUS_SUCCESS); 3875 } 3876 3877 /* 3878 * Invoked after processing of an inbound packet by the 3879 * kernel crypto framework. Called by ah_submit_req() for a sync request, 3880 * or by the kcf callback for an async request. 3881 * Returns IPSEC_STATUS_SUCCESS on success, IPSEC_STATUS_FAILED on failure. 3882 * On failure, the mblk chain ipsec_in is freed by this function. 3883 */ 3884 static ipsec_status_t 3885 ah_auth_in_done(mblk_t *ipsec_in) 3886 { 3887 mblk_t *phdr_mp; 3888 ipha_t *ipha; 3889 uint_t ah_offset = 0; 3890 mblk_t *mp; 3891 int align_len; 3892 ah_t *ah; 3893 ipha_t *nipha; 3894 uint32_t length; 3895 ipsec_in_t *ii; 3896 boolean_t isv4; 3897 ip6_t *ip6h; 3898 ip6_t *nip6h; 3899 uint_t icv_len; 3900 ipsa_t *assoc; 3901 kstat_named_t *counter; 3902 3903 ii = (ipsec_in_t *)ipsec_in->b_rptr; 3904 isv4 = ii->ipsec_in_v4; 3905 assoc = ii->ipsec_in_ah_sa; 3906 icv_len = (uint_t)ii->ipsec_in_crypto_mac.cd_raw.iov_len; 3907 3908 phdr_mp = ipsec_in->b_cont; 3909 if (phdr_mp == NULL) { 3910 ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, &ipdrops_ah_nomem, 3911 &ah_dropper); 3912 return (IPSEC_STATUS_FAILED); 3913 } 3914 3915 mp = phdr_mp->b_cont; 3916 if (mp == NULL) { 3917 ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, &ipdrops_ah_nomem, 3918 &ah_dropper); 3919 return (IPSEC_STATUS_FAILED); 3920 } 3921 mp->b_rptr -= ii->ipsec_in_skip_len; 3922 3923 if (isv4) { 3924 ipha = (ipha_t *)mp->b_rptr; 3925 ah_offset = ipha->ipha_version_and_hdr_length - 3926 (uint8_t)((IP_VERSION << 4)); 3927 ah_offset <<= 2; 3928 align_len = P2ALIGN(icv_len + IPV4_PADDING_ALIGN - 1, 3929 IPV4_PADDING_ALIGN); 3930 } else { 3931 ip6h = (ip6_t *)mp->b_rptr; 3932 ah_offset = ipsec_ah_get_hdr_size_v6(mp, B_TRUE); 3933 ASSERT((mp->b_wptr - mp->b_rptr) >= ah_offset); 3934 align_len = P2ALIGN(icv_len + IPV6_PADDING_ALIGN - 1, 3935 IPV6_PADDING_ALIGN); 3936 } 3937 3938 ah = (ah_t *)(mp->b_rptr + ah_offset); 3939 3940 /* 3941 * We get here only when authentication passed. 3942 */ 3943 3944 ah3dbg(("AH succeeded, checking replay\n")); 3945 AH_BUMP_STAT(good_auth); 3946 3947 if (!sadb_replay_check(assoc, ah->ah_replay)) { 3948 int af; 3949 void *addr; 3950 3951 if (isv4) { 3952 addr = &ipha->ipha_dst; 3953 af = AF_INET; 3954 } else { 3955 addr = &ip6h->ip6_dst; 3956 af = AF_INET6; 3957 } 3958 3959 /* 3960 * Log the event. As of now we print out an event. 3961 * Do not print the replay failure number, or else 3962 * syslog cannot collate the error messages. Printing 3963 * the replay number that failed (or printing to the 3964 * console) opens a denial-of-service attack. 3965 */ 3966 AH_BUMP_STAT(replay_failures); 3967 ipsec_assocfailure(info.mi_idnum, 0, 0, 3968 SL_ERROR | SL_WARN, 3969 "Replay failed for AH spi %x, dst_addr %s", 3970 assoc->ipsa_spi, addr, af); 3971 counter = &ipdrops_ah_replay; 3972 goto ah_in_discard; 3973 } 3974 3975 /* 3976 * We need to remove the AH header from the original 3977 * datagram. Easy way to do this is to use phdr_mp 3978 * to hold the IP header and the orginal mp to hold 3979 * the rest of it. So, we copy the IP header on to 3980 * phdr_mp, and set the b_rptr in mp past AH header. 3981 */ 3982 if (isv4) { 3983 bcopy(mp->b_rptr, phdr_mp->b_rptr, ah_offset); 3984 phdr_mp->b_wptr = phdr_mp->b_rptr + ah_offset; 3985 nipha = (ipha_t *)phdr_mp->b_rptr; 3986 /* 3987 * Assign the right protocol, adjust the length as we 3988 * are removing the AH header and adjust the checksum to 3989 * account for the protocol and length. 3990 */ 3991 nipha->ipha_protocol = ah->ah_nexthdr; 3992 length = ntohs(nipha->ipha_length); 3993 if (!ah_age_bytes(assoc, length, B_TRUE)) { 3994 /* The ipsa has hit hard expiration, LOG and AUDIT. */ 3995 ipsec_assocfailure(info.mi_idnum, 0, 0, 3996 SL_ERROR | SL_WARN, 3997 "AH Association 0x%x, dst %s had bytes expire.\n", 3998 assoc->ipsa_spi, assoc->ipsa_dstaddr, 3999 AF_INET); 4000 AH_BUMP_STAT(bytes_expired); 4001 counter = &ipdrops_ah_bytes_expire; 4002 goto ah_in_discard; 4003 } 4004 length -= (sizeof (ah_t) + align_len); 4005 4006 nipha->ipha_length = htons((uint16_t)length); 4007 nipha->ipha_hdr_checksum = 0; 4008 nipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(nipha); 4009 /* 4010 * Skip IP,AH and the authentication data in the 4011 * original datagram. 4012 */ 4013 mp->b_rptr += (ah_offset + sizeof (ah_t) + align_len); 4014 } else { 4015 uchar_t *whereptr; 4016 int hdrlen; 4017 uint8_t *nexthdr; 4018 ip6_hbh_t *hbhhdr; 4019 ip6_dest_t *dsthdr; 4020 ip6_rthdr0_t *rthdr; 4021 4022 nip6h = (ip6_t *)phdr_mp->b_rptr; 4023 4024 /* 4025 * Make phdr_mp hold until the AH header and make 4026 * mp hold everything past AH header. 4027 */ 4028 length = ntohs(nip6h->ip6_plen); 4029 if (!ah_age_bytes(assoc, length + sizeof (ip6_t), B_TRUE)) { 4030 /* The ipsa has hit hard expiration, LOG and AUDIT. */ 4031 ipsec_assocfailure(info.mi_idnum, 0, 0, 4032 SL_ERROR | SL_WARN, 4033 "AH Association 0x%x, dst %s had bytes " 4034 "expire.\n", assoc->ipsa_spi, &ip6h->ip6_dst, 4035 AF_INET6); 4036 AH_BUMP_STAT(bytes_expired); 4037 counter = &ipdrops_ah_bytes_expire; 4038 goto ah_in_discard; 4039 } 4040 bcopy(ip6h, nip6h, ah_offset); 4041 phdr_mp->b_wptr = phdr_mp->b_rptr + ah_offset; 4042 mp->b_rptr += (ah_offset + sizeof (ah_t) + align_len); 4043 4044 /* 4045 * Update the next header field of the header preceding 4046 * AH with the next header field of AH. Start with the 4047 * IPv6 header and proceed with the extension headers 4048 * until we find what we're looking for. 4049 */ 4050 nexthdr = &nip6h->ip6_nxt; 4051 whereptr = (uchar_t *)nip6h; 4052 hdrlen = sizeof (ip6_t); 4053 4054 while (*nexthdr != IPPROTO_AH) { 4055 whereptr += hdrlen; 4056 /* Assume IP has already stripped it */ 4057 ASSERT(*nexthdr != IPPROTO_FRAGMENT && 4058 *nexthdr != IPPROTO_RAW); 4059 switch (*nexthdr) { 4060 case IPPROTO_HOPOPTS: 4061 hbhhdr = (ip6_hbh_t *)whereptr; 4062 nexthdr = &hbhhdr->ip6h_nxt; 4063 hdrlen = 8 * (hbhhdr->ip6h_len + 1); 4064 break; 4065 case IPPROTO_DSTOPTS: 4066 dsthdr = (ip6_dest_t *)whereptr; 4067 nexthdr = &dsthdr->ip6d_nxt; 4068 hdrlen = 8 * (dsthdr->ip6d_len + 1); 4069 break; 4070 case IPPROTO_ROUTING: 4071 rthdr = (ip6_rthdr0_t *)whereptr; 4072 nexthdr = &rthdr->ip6r0_nxt; 4073 hdrlen = 8 * (rthdr->ip6r0_len + 1); 4074 break; 4075 } 4076 } 4077 *nexthdr = ah->ah_nexthdr; 4078 4079 length -= (sizeof (ah_t) + align_len); 4080 nip6h->ip6_plen = htons((uint16_t)length); 4081 } 4082 4083 return (IPSEC_STATUS_SUCCESS); 4084 4085 ah_in_discard: 4086 IP_AH_BUMP_STAT(in_discards); 4087 ip_drop_packet(ipsec_in, B_TRUE, NULL, NULL, counter, &ah_dropper); 4088 return (IPSEC_STATUS_FAILED); 4089 } 4090 4091 /* 4092 * Invoked after processing of an outbound packet by the 4093 * kernel crypto framework, either by ah_submit_req() for a request 4094 * executed syncrhonously, or by the KEF callback for a request 4095 * executed asynchronously. 4096 */ 4097 static ipsec_status_t 4098 ah_auth_out_done(mblk_t *ipsec_out) 4099 { 4100 mblk_t *phdr_mp; 4101 mblk_t *mp; 4102 int align_len; 4103 uint32_t hdrs_length; 4104 uchar_t *ptr; 4105 uint32_t length; 4106 boolean_t isv4; 4107 ipsec_out_t *io; 4108 size_t icv_len; 4109 4110 io = (ipsec_out_t *)ipsec_out->b_rptr; 4111 isv4 = io->ipsec_out_v4; 4112 icv_len = io->ipsec_out_crypto_mac.cd_raw.iov_len; 4113 4114 phdr_mp = ipsec_out->b_cont; 4115 if (phdr_mp == NULL) { 4116 ip_drop_packet(ipsec_out, B_FALSE, NULL, NULL, 4117 &ipdrops_ah_nomem, &ah_dropper); 4118 return (IPSEC_STATUS_FAILED); 4119 } 4120 4121 mp = phdr_mp->b_cont; 4122 if (mp == NULL) { 4123 ip_drop_packet(ipsec_out, B_FALSE, NULL, NULL, 4124 &ipdrops_ah_nomem, &ah_dropper); 4125 return (IPSEC_STATUS_FAILED); 4126 } 4127 mp->b_rptr -= io->ipsec_out_skip_len; 4128 4129 if (isv4) { 4130 ipha_t *ipha; 4131 ipha_t *nipha; 4132 4133 ipha = (ipha_t *)mp->b_rptr; 4134 hdrs_length = ipha->ipha_version_and_hdr_length - 4135 (uint8_t)((IP_VERSION << 4)); 4136 hdrs_length <<= 2; 4137 align_len = P2ALIGN(icv_len + IPV4_PADDING_ALIGN - 1, 4138 IPV4_PADDING_ALIGN); 4139 /* 4140 * phdr_mp must have the right amount of space for the 4141 * combined IP and AH header. Copy the IP header and 4142 * the ack_data onto AH. Note that the AH header was 4143 * already formed before the ICV calculation and hence 4144 * you don't have to copy it here. 4145 */ 4146 bcopy(mp->b_rptr, phdr_mp->b_rptr, hdrs_length); 4147 4148 ptr = phdr_mp->b_rptr + hdrs_length + sizeof (ah_t); 4149 bcopy(phdr_mp->b_wptr, ptr, icv_len); 4150 4151 /* 4152 * Compute the new header checksum as we are assigning 4153 * IPPROTO_AH and adjusting the length here. 4154 */ 4155 nipha = (ipha_t *)phdr_mp->b_rptr; 4156 4157 nipha->ipha_protocol = IPPROTO_AH; 4158 length = ntohs(nipha->ipha_length); 4159 length += (sizeof (ah_t) + align_len); 4160 nipha->ipha_length = htons((uint16_t)length); 4161 nipha->ipha_hdr_checksum = 0; 4162 nipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(nipha); 4163 } else { 4164 ip6_t *ip6h; 4165 ip6_t *nip6h; 4166 uint_t ah_offset; 4167 4168 ip6h = (ip6_t *)mp->b_rptr; 4169 nip6h = (ip6_t *)phdr_mp->b_rptr; 4170 align_len = P2ALIGN(icv_len + IPV6_PADDING_ALIGN - 1, 4171 IPV6_PADDING_ALIGN); 4172 /* 4173 * phdr_mp must have the right amount of space for the 4174 * combined IP and AH header. Copy the IP header with 4175 * options into the pseudo header. When we constructed 4176 * a pseudo header, we did not copy some of the mutable 4177 * fields. We do it now by calling ah_fix_phdr_v6() 4178 * with the last argument B_TRUE. It returns the 4179 * ah_offset into the pseudo header. 4180 */ 4181 4182 bcopy(ip6h, nip6h, IPV6_HDR_LEN); 4183 ah_offset = ah_fix_phdr_v6(nip6h, ip6h, B_TRUE, B_TRUE); 4184 ASSERT(ah_offset != 0); 4185 /* 4186 * phdr_mp can hold exactly the whole IP header with options 4187 * plus the AH header also. Thus subtracting the AH header's 4188 * size should give exactly how much of the original header 4189 * should be skipped. 4190 */ 4191 hdrs_length = (phdr_mp->b_wptr - phdr_mp->b_rptr) - 4192 sizeof (ah_t) - icv_len; 4193 bcopy(phdr_mp->b_wptr, ((uint8_t *)nip6h + ah_offset + 4194 sizeof (ah_t)), icv_len); 4195 length = ntohs(nip6h->ip6_plen); 4196 length += (sizeof (ah_t) + align_len); 4197 nip6h->ip6_plen = htons((uint16_t)length); 4198 } 4199 4200 /* Skip the original IP header */ 4201 mp->b_rptr += hdrs_length; 4202 if (mp->b_rptr == mp->b_wptr) { 4203 phdr_mp->b_cont = mp->b_cont; 4204 freeb(mp); 4205 } 4206 4207 return (IPSEC_STATUS_SUCCESS); 4208 } 4209 4210 /* 4211 * Wrapper to allow IP to trigger an AH association failure message 4212 * during SA inbound selection. 4213 */ 4214 void 4215 ipsecah_in_assocfailure(mblk_t *mp, char level, ushort_t sl, char *fmt, 4216 uint32_t spi, void *addr, int af) 4217 { 4218 if (ipsecah_log_unknown_spi) { 4219 ipsec_assocfailure(info.mi_idnum, 0, level, sl, fmt, spi, 4220 addr, af); 4221 } 4222 4223 ip_drop_packet(mp, B_TRUE, NULL, NULL, &ipdrops_ah_no_sa, 4224 &ah_dropper); 4225 } 4226 4227 /* 4228 * Initialize the AH input and output processing functions. 4229 */ 4230 void 4231 ipsecah_init_funcs(ipsa_t *sa) 4232 { 4233 if (sa->ipsa_output_func == NULL) 4234 sa->ipsa_output_func = ah_outbound; 4235 if (sa->ipsa_input_func == NULL) 4236 sa->ipsa_input_func = ah_inbound; 4237 } 4238