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