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