1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2024 Oxide Computer Company 14 */ 15 16 /* 17 * RFC 2385 TCP MD5 Signature Option 18 * 19 * A security option commonly used to enhance security for BGP sessions. When a 20 * TCP socket has its TCP_MD5SIG option enabled, an additional TCP option is 21 * added to the header containing an MD5 digest calculated across the pseudo IP 22 * header, part of the TCP header, the data in the segment and a shared secret. 23 * The option is large (18 bytes plus 2 more for padding to a word boundary), 24 * and often /just/ fits in the TCP header -- particularly with SYN packets due 25 * to their additional options such as MSS. 26 * 27 * The socket option is boolean, and it is also necessary to have configured a 28 * security association (SA) to match the traffic that should be signed, and to 29 * provide the signing key. These SAs are configured from userland via 30 * tcpkey(8), use source and destination addresses and ports as criteria, and 31 * are maintained in a per-netstack linked list. The SAs pertaining to a 32 * particular TCP connection, one for each direction, are cached in the 33 * connection's TCP state after the first packet has been processed, and so 34 * using a single list is not a significant overhead, particularly as it is 35 * expected to be short. 36 * 37 * Enabling the socket option has a number of side effects: 38 * 39 * - TCP fast path is disabled; 40 * - TCP Fusion is disabled; 41 * - Outbound packets for which a matching SA cannot be found are silently 42 * discarded. 43 * - Inbound packets that DO NOT contain an MD5 option in their TCP header are 44 * silently discarded. 45 * - Inbound packets that DO contain an MD5 option but for which the digest 46 * does not match the locally calculated one are silently discarded. 47 * 48 * An SA is bound to a TCP stream once the first packet is sent or received 49 * following the TCP_MD5SIG socket option being enabled. Typically an 50 * application will enable the socket option immediately after creating the 51 * socket, and before moving on to calling connect() or bind() but it is 52 * necessary to wait for the first packet as that is the point at which the 53 * source and destination addresses and ports are all known, and we need these 54 * to find the SA. Note that if no matching SA is present in the database when 55 * the first packet is sent or received, it will be silently dropped. Due to 56 * the reference counting and tombstone logic, an SA that has been bound to one 57 * or more streams will persist until all of those streams have been torn down. 58 * It is not possible to change the SA for an active connection. 59 * 60 * ------------- 61 * Lock Ordering 62 * ------------- 63 * 64 * In order to ensure that we don't deadlock, if both are required, the RW lock 65 * across the SADB must be taken before acquiring an individual SA's lock. That 66 * is, locks must be taken in the following order (and released in the opposite 67 * order): 68 * 69 * 0) <tcpstack>->tcps_sigdb->td_lock 70 * 1) <tcpstack>->tcps_sigdb->td_sa.list-><entry>->ts_lock 71 * 72 * The lock at <tcpstack>->tcps_sigdb_lock is independent and used to 73 * synchronize lazy initialization of the database. 74 */ 75 76 #include <sys/atomic.h> 77 #include <sys/cmn_err.h> 78 #include <sys/cpuvar.h> 79 #include <sys/debug.h> 80 #include <sys/errno.h> 81 #include <sys/kmem.h> 82 #include <sys/list.h> 83 #include <sys/md5.h> 84 #include <sys/stdbool.h> 85 #include <sys/stream.h> 86 #include <sys/stropts.h> 87 #include <sys/strsubr.h> 88 #include <sys/strsun.h> 89 #include <sys/sysmacros.h> 90 #include <sys/types.h> 91 #include <netinet/in.h> 92 #include <netinet/ip6.h> 93 #include <net/pfkeyv2.h> 94 #include <net/pfpolicy.h> 95 #include <inet/common.h> 96 #include <inet/mi.h> 97 #include <inet/ip.h> 98 #include <inet/ip6.h> 99 #include <inet/ip_if.h> 100 #include <inet/tcp_stats.h> 101 #include <inet/keysock.h> 102 #include <inet/sadb.h> 103 #include <inet/tcp_sig.h> 104 105 static void tcpsig_sa_free(tcpsig_sa_t *); 106 107 void 108 tcpsig_init(tcp_stack_t *tcps) 109 { 110 mutex_init(&tcps->tcps_sigdb_lock, NULL, MUTEX_DEFAULT, NULL); 111 } 112 113 void 114 tcpsig_fini(tcp_stack_t *tcps) 115 { 116 tcpsig_db_t *db; 117 118 if ((db = tcps->tcps_sigdb) != NULL) { 119 tcpsig_sa_t *sa; 120 121 rw_destroy(&db->td_lock); 122 while ((sa = list_remove_head(&db->td_salist)) != NULL) 123 tcpsig_sa_free(sa); 124 list_destroy(&db->td_salist); 125 kmem_free(tcps->tcps_sigdb, sizeof (tcpsig_db_t)); 126 tcps->tcps_sigdb = NULL; 127 } 128 mutex_destroy(&tcps->tcps_sigdb_lock); 129 } 130 131 static tcpsig_db_t * 132 tcpsig_db(tcp_stack_t *tcps) 133 { 134 mutex_enter(&tcps->tcps_sigdb_lock); 135 if (tcps->tcps_sigdb == NULL) { 136 tcpsig_db_t *db = kmem_alloc(sizeof (tcpsig_db_t), KM_SLEEP); 137 138 rw_init(&db->td_lock, NULL, RW_DEFAULT, 0); 139 list_create(&db->td_salist, sizeof (tcpsig_sa_t), 140 offsetof(tcpsig_sa_t, ts_link)); 141 142 tcps->tcps_sigdb = db; 143 } 144 mutex_exit(&tcps->tcps_sigdb_lock); 145 146 return ((tcpsig_db_t *)tcps->tcps_sigdb); 147 } 148 149 static uint8_t * 150 tcpsig_make_sa_ext(uint8_t *start, const uint8_t * const end, 151 const tcpsig_sa_t *sa) 152 { 153 sadb_sa_t *assoc; 154 155 ASSERT3P(end, >, start); 156 157 if (start == NULL || end - start < sizeof (*assoc)) 158 return (NULL); 159 160 assoc = (sadb_sa_t *)start; 161 assoc->sadb_sa_exttype = SADB_EXT_SA; 162 assoc->sadb_sa_len = SADB_8TO64(sizeof (*assoc)); 163 assoc->sadb_sa_auth = sa->ts_key.sak_algid; 164 assoc->sadb_sa_flags = SADB_X_SAFLAGS_TCPSIG; 165 assoc->sadb_sa_state = sa->ts_state; 166 167 return ((uint8_t *)(assoc + 1)); 168 } 169 170 static size_t 171 tcpsig_addr_extsize(const tcpsig_sa_t *sa) 172 { 173 size_t addrsize = 0; 174 175 switch (sa->ts_family) { 176 case AF_INET: 177 addrsize = roundup(sizeof (sin_t) + 178 sizeof (sadb_address_t), sizeof (uint64_t)); 179 break; 180 case AF_INET6: 181 addrsize = roundup(sizeof (sin6_t) + 182 sizeof (sadb_address_t), sizeof (uint64_t)); 183 break; 184 } 185 return (addrsize); 186 } 187 188 static uint8_t * 189 tcpsig_make_addr_ext(uint8_t *start, const uint8_t * const end, 190 uint16_t exttype, sa_family_t af, const struct sockaddr_storage *addr) 191 { 192 uint8_t *cur = start; 193 unsigned int addrext_len; 194 sadb_address_t *addrext; 195 196 ASSERT(af == AF_INET || af == AF_INET6); 197 ASSERT3P(end, >, start); 198 199 if (cur == NULL) 200 return (NULL); 201 202 if (end - cur < sizeof (*addrext)) 203 return (NULL); 204 205 addrext = (sadb_address_t *)cur; 206 addrext->sadb_address_proto = IPPROTO_TCP; 207 addrext->sadb_address_reserved = 0; 208 addrext->sadb_address_prefixlen = 0; 209 addrext->sadb_address_exttype = exttype; 210 cur = (uint8_t *)(addrext + 1); 211 212 if (af == AF_INET) { 213 sin_t *sin; 214 215 if (end - cur < sizeof (*sin)) 216 return (NULL); 217 sin = (sin_t *)cur; 218 219 *sin = sin_null; 220 bcopy(addr, sin, sizeof (*sin)); 221 cur = (uint8_t *)(sin + 1); 222 } else { 223 sin6_t *sin6; 224 225 if (end - cur < sizeof (*sin6)) 226 return (NULL); 227 sin6 = (sin6_t *)cur; 228 229 *sin6 = sin6_null; 230 bcopy(addr, sin6, sizeof (*sin6)); 231 cur = (uint8_t *)(sin6 + 1); 232 } 233 234 addrext_len = roundup(cur - start, sizeof (uint64_t)); 235 addrext->sadb_address_len = SADB_8TO64(addrext_len); 236 237 if (end - start < addrext_len) 238 return (NULL); 239 return (start + addrext_len); 240 } 241 242 #define SET_EXPIRE(sa, delta, exp) do { \ 243 if (((sa)->ts_ ## delta) != 0) { \ 244 (sa)->ts_ ## exp = tcpsig_add_time((sa)->ts_addtime, \ 245 (sa)->ts_ ## delta); \ 246 } \ 247 } while (0) 248 249 #define UPDATE_EXPIRE(sa, delta, exp) do { \ 250 if (((sa)->ts_ ## delta) != 0) { \ 251 time_t tmp = tcpsig_add_time((sa)->ts_usetime, \ 252 (sa)->ts_ ## delta); \ 253 if (((sa)->ts_ ## exp) == 0) \ 254 (sa)->ts_ ## exp = tmp; \ 255 else \ 256 (sa)->ts_ ## exp = MIN((sa)->ts_ ## exp, tmp); \ 257 } \ 258 } while (0) 259 260 #define EXPIRED(sa, exp, now) \ 261 ((sa)->ts_ ## exp != 0 && sa->ts_ ## exp < (now)) 262 263 /* 264 * PF_KEY gives us lifetimes in uint64_t seconds. In order to avoid odd 265 * behaviour (either negative lifetimes or loss of high order bits) when 266 * someone asks for bizarrely long SA lifetimes, we do a saturating add for 267 * expire times. 268 */ 269 #define TIME_MAX INT64_MAX 270 static time_t 271 tcpsig_add_time(time_t base, uint64_t delta) 272 { 273 if (delta > TIME_MAX) 274 delta = TIME_MAX; 275 276 if (base > 0) { 277 if (TIME_MAX - base < delta) 278 return (TIME_MAX); 279 } 280 281 return (base + delta); 282 } 283 284 /* 285 * Check hard/soft liftimes and return an appropriate error. 286 */ 287 static int 288 tcpsig_check_lifetimes(sadb_lifetime_t *hard, sadb_lifetime_t *soft) 289 { 290 if (hard == NULL || soft == NULL) 291 return (SADB_X_DIAGNOSTIC_NONE); 292 293 if (hard->sadb_lifetime_addtime != 0 && 294 soft->sadb_lifetime_addtime != 0 && 295 hard->sadb_lifetime_addtime < soft->sadb_lifetime_addtime) { 296 return (SADB_X_DIAGNOSTIC_ADDTIME_HSERR); 297 } 298 299 if (hard->sadb_lifetime_usetime != 0 && 300 soft->sadb_lifetime_usetime != 0 && 301 hard->sadb_lifetime_usetime < soft->sadb_lifetime_usetime) { 302 return (SADB_X_DIAGNOSTIC_USETIME_HSERR); 303 } 304 305 return (SADB_X_DIAGNOSTIC_NONE); 306 } 307 308 /* 309 * Update the lifetime values of an SA. 310 * If the updated lifetimes mean that a previously dying or dead SA should be 311 * promoted back to mature, then do that too. However, if they would mean that 312 * the SA is immediately expired, then that will be handled on the next 313 * aging run. 314 */ 315 static void 316 tcpsig_update_lifetimes(tcpsig_sa_t *sa, sadb_lifetime_t *hard, 317 sadb_lifetime_t *soft) 318 { 319 const time_t now = gethrestime_sec(); 320 321 mutex_enter(&sa->ts_lock); 322 323 if (hard != NULL) { 324 if (hard->sadb_lifetime_usetime != 0) 325 sa->ts_harduselt = hard->sadb_lifetime_usetime; 326 if (hard->sadb_lifetime_addtime != 0) 327 sa->ts_hardaddlt = hard->sadb_lifetime_addtime; 328 if (sa->ts_hardaddlt != 0) 329 SET_EXPIRE(sa, hardaddlt, hardexpiretime); 330 if (sa->ts_harduselt != 0 && sa->ts_usetime != 0) 331 UPDATE_EXPIRE(sa, harduselt, hardexpiretime); 332 if (sa->ts_state == SADB_SASTATE_DEAD && 333 !EXPIRED(sa, hardexpiretime, now)) { 334 sa->ts_state = SADB_SASTATE_MATURE; 335 } 336 } 337 338 if (soft != NULL) { 339 if (soft->sadb_lifetime_usetime != 0) { 340 sa->ts_softuselt = MIN(sa->ts_harduselt, 341 soft->sadb_lifetime_usetime); 342 } 343 if (soft->sadb_lifetime_addtime != 0) { 344 sa->ts_softaddlt = MIN(sa->ts_hardaddlt, 345 soft->sadb_lifetime_addtime); 346 } 347 if (sa->ts_softaddlt != 0) 348 SET_EXPIRE(sa, softaddlt, softexpiretime); 349 if (sa->ts_softuselt != 0 && sa->ts_usetime != 0) 350 UPDATE_EXPIRE(sa, softuselt, softexpiretime); 351 if (sa->ts_state == SADB_SASTATE_DYING && 352 !EXPIRED(sa, softexpiretime, now)) { 353 sa->ts_state = SADB_SASTATE_MATURE; 354 } 355 } 356 357 mutex_exit(&sa->ts_lock); 358 } 359 360 static void 361 tcpsig_sa_touch(tcpsig_sa_t *sa) 362 { 363 const time_t now = gethrestime_sec(); 364 365 mutex_enter(&sa->ts_lock); 366 sa->ts_lastuse = now; 367 368 if (sa->ts_usetime == 0) { 369 sa->ts_usetime = now; 370 /* Update expiry times following the first use */ 371 UPDATE_EXPIRE(sa, softuselt, softexpiretime); 372 UPDATE_EXPIRE(sa, harduselt, hardexpiretime); 373 } 374 mutex_exit(&sa->ts_lock); 375 } 376 377 static void 378 tcpsig_sa_expiremsg(keysock_t *ks, const tcpsig_sa_t *sa, int ltt) 379 { 380 size_t alloclen; 381 sadb_sa_t *assoc; 382 sadb_msg_t *samsg; 383 sadb_lifetime_t *lt; 384 uint8_t *cur, *end; 385 mblk_t *mp; 386 387 alloclen = sizeof (sadb_msg_t) + sizeof (sadb_sa_t) + 388 2 * sizeof (sadb_lifetime_t) + 2 * tcpsig_addr_extsize(sa); 389 390 mp = allocb(alloclen, BPRI_HI); 391 if (mp == NULL) 392 return; 393 394 bzero(mp->b_rptr, alloclen); 395 mp->b_wptr += alloclen; 396 end = mp->b_wptr; 397 398 samsg = (sadb_msg_t *)mp->b_rptr; 399 samsg->sadb_msg_version = PF_KEY_V2; 400 samsg->sadb_msg_type = SADB_EXPIRE; 401 samsg->sadb_msg_errno = 0; 402 samsg->sadb_msg_satype = SADB_X_SATYPE_TCPSIG; 403 samsg->sadb_msg_reserved = 0; 404 samsg->sadb_msg_seq = 0; 405 samsg->sadb_msg_pid = 0; 406 samsg->sadb_msg_len = (uint16_t)SADB_8TO64(alloclen); 407 408 cur = (uint8_t *)(samsg + 1); 409 cur = tcpsig_make_sa_ext(cur, end, sa); 410 cur = tcpsig_make_addr_ext(cur, end, SADB_EXT_ADDRESS_SRC, 411 sa->ts_family, &sa->ts_src); 412 cur = tcpsig_make_addr_ext(cur, end, SADB_EXT_ADDRESS_DST, 413 sa->ts_family, &sa->ts_dst); 414 415 if (cur == NULL) { 416 freeb(mp); 417 return; 418 } 419 420 lt = (sadb_lifetime_t *)cur; 421 lt->sadb_lifetime_len = SADB_8TO64(sizeof (*lt)); 422 lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; 423 lt->sadb_lifetime_allocations = 0; 424 lt->sadb_lifetime_bytes = 0; 425 lt->sadb_lifetime_addtime = sa->ts_addtime; 426 lt->sadb_lifetime_usetime = sa->ts_usetime; 427 428 lt++; 429 lt->sadb_lifetime_len = SADB_8TO64(sizeof (*lt)); 430 lt->sadb_lifetime_exttype = ltt; 431 lt->sadb_lifetime_allocations = 0; 432 lt->sadb_lifetime_bytes = 0; 433 lt->sadb_lifetime_addtime = sa->ts_hardaddlt; 434 lt->sadb_lifetime_usetime = sa->ts_harduselt; 435 436 keysock_passup(mp, (sadb_msg_t *)mp->b_rptr, 437 0, NULL, B_TRUE, ks->keysock_keystack); 438 } 439 440 static void 441 tcpsig_sa_age(keysock_t *ks, tcp_stack_t *tcps) 442 { 443 tcpsig_db_t *db = tcpsig_db(tcps); 444 tcpsig_sa_t *nextsa; 445 const time_t now = gethrestime_sec(); 446 447 rw_enter(&db->td_lock, RW_WRITER); 448 nextsa = list_head(&db->td_salist); 449 while (nextsa != NULL) { 450 tcpsig_sa_t *sa = nextsa; 451 452 nextsa = list_next(&db->td_salist, sa); 453 454 mutex_enter(&sa->ts_lock); 455 456 if (sa->ts_tombstoned) { 457 mutex_exit(&sa->ts_lock); 458 continue; 459 } 460 461 if (EXPIRED(sa, hardexpiretime, now)) { 462 sa->ts_state = IPSA_STATE_DEAD; 463 tcpsig_sa_expiremsg(ks, sa, SADB_EXT_LIFETIME_HARD); 464 if (sa->ts_refcnt > 0) { 465 sa->ts_tombstoned = true; 466 mutex_exit(&sa->ts_lock); 467 } else { 468 list_remove(&db->td_salist, sa); 469 mutex_exit(&sa->ts_lock); 470 tcpsig_sa_free(sa); 471 } 472 continue; 473 } 474 475 if (EXPIRED(sa, softexpiretime, now) && 476 sa->ts_state == IPSA_STATE_MATURE) { 477 sa->ts_state = IPSA_STATE_DYING; 478 tcpsig_sa_expiremsg(ks, sa, SADB_EXT_LIFETIME_SOFT); 479 } 480 481 mutex_exit(&sa->ts_lock); 482 } 483 484 rw_exit(&db->td_lock); 485 } 486 487 static void 488 tcpsig_sa_free(tcpsig_sa_t *sa) 489 { 490 ASSERT0(sa->ts_refcnt); 491 mutex_destroy(&sa->ts_lock); 492 kmem_free(sa->ts_key.sak_key, sa->ts_key.sak_keylen); 493 kmem_free(sa, sizeof (*sa)); 494 } 495 496 void 497 tcpsig_sa_rele(tcpsig_sa_t *sa) 498 { 499 mutex_enter(&sa->ts_lock); 500 VERIFY3U(sa->ts_refcnt, >, 0); 501 sa->ts_refcnt--; 502 /* 503 * If we are tombstoned (have been marked as deleted) and the reference 504 * count has now dropped to zero, then we can go ahead and finally 505 * remove this SA from the database. 506 */ 507 if (sa->ts_tombstoned && sa->ts_refcnt == 0) { 508 tcpsig_db_t *db = tcpsig_db(sa->ts_stack); 509 510 /* 511 * To maintain the required lock ordering, we need to drop the 512 * lock on the SA while acquiring the RW lock on the list. Take 513 * an additional hold before doing this dance and drop it once 514 * we have re-gained the lock. 515 */ 516 sa->ts_refcnt++; 517 mutex_exit(&sa->ts_lock); 518 rw_enter(&db->td_lock, RW_WRITER); 519 mutex_enter(&sa->ts_lock); 520 sa->ts_refcnt--; 521 mutex_exit(&sa->ts_lock); 522 523 list_remove(&db->td_salist, sa); 524 525 rw_exit(&db->td_lock); 526 tcpsig_sa_free(sa); 527 } else { 528 mutex_exit(&sa->ts_lock); 529 } 530 } 531 532 static bool 533 tcpsig_sa_match4(tcpsig_sa_t *sa, struct sockaddr_storage *src_s, 534 struct sockaddr_storage *dst_s) 535 { 536 sin_t msrc, mdst, *src, *dst, *sasrc, *sadst; 537 538 if (src_s->ss_family != AF_INET) 539 return (false); 540 541 src = (sin_t *)src_s; 542 dst = (sin_t *)dst_s; 543 544 if (sa->ts_family == AF_INET6) { 545 sin6_t *sasrc6 = (sin6_t *)&sa->ts_src; 546 sin6_t *sadst6 = (sin6_t *)&sa->ts_dst; 547 548 if (!IN6_IS_ADDR_V4MAPPED(&sasrc6->sin6_addr) || 549 !IN6_IS_ADDR_V4MAPPED(&sadst6->sin6_addr)) { 550 return (false); 551 } 552 553 msrc = sin_null; 554 msrc.sin_family = AF_INET; 555 msrc.sin_port = sasrc6->sin6_port; 556 IN6_V4MAPPED_TO_INADDR(&sasrc6->sin6_addr, &msrc.sin_addr); 557 sasrc = &msrc; 558 559 mdst = sin_null; 560 mdst.sin_family = AF_INET; 561 mdst.sin_port = sadst6->sin6_port; 562 IN6_V4MAPPED_TO_INADDR(&sadst6->sin6_addr, &mdst.sin_addr); 563 sadst = &mdst; 564 } else { 565 sasrc = (sin_t *)&sa->ts_src; 566 sadst = (sin_t *)&sa->ts_dst; 567 } 568 569 if (sasrc->sin_port != 0 && sasrc->sin_port != src->sin_port) 570 return (false); 571 if (sadst->sin_port != 0 && sadst->sin_port != dst->sin_port) 572 return (false); 573 574 if (sasrc->sin_addr.s_addr != src->sin_addr.s_addr) 575 return (false); 576 if (sadst->sin_addr.s_addr != dst->sin_addr.s_addr) 577 return (false); 578 579 return (true); 580 } 581 582 static bool 583 tcpsig_sa_match6(tcpsig_sa_t *sa, struct sockaddr_storage *src_s, 584 struct sockaddr_storage *dst_s) 585 { 586 sin6_t *src, *dst, *sasrc, *sadst; 587 588 if (src_s->ss_family != AF_INET6 || sa->ts_src.ss_family != AF_INET6) 589 return (false); 590 591 src = (sin6_t *)src_s; 592 dst = (sin6_t *)dst_s; 593 594 sasrc = (sin6_t *)&sa->ts_src; 595 sadst = (sin6_t *)&sa->ts_dst; 596 597 if (sasrc->sin6_port != 0 && sasrc->sin6_port != src->sin6_port) 598 return (false); 599 if (sadst->sin6_port != 0 && sadst->sin6_port != dst->sin6_port) 600 return (false); 601 602 if (!IN6_ARE_ADDR_EQUAL(&sasrc->sin6_addr, &src->sin6_addr)) 603 return (false); 604 if (!IN6_ARE_ADDR_EQUAL(&sadst->sin6_addr, &dst->sin6_addr)) 605 return (false); 606 607 return (true); 608 } 609 610 static tcpsig_sa_t * 611 tcpsig_sa_find_held(struct sockaddr_storage *src, struct sockaddr_storage *dst, 612 tcp_stack_t *tcps) 613 { 614 tcpsig_db_t *db = tcpsig_db(tcps); 615 tcpsig_sa_t *sa = NULL; 616 const time_t now = gethrestime_sec(); 617 618 ASSERT(RW_LOCK_HELD(&db->td_lock)); 619 620 if (src->ss_family != dst->ss_family) 621 return (NULL); 622 623 for (sa = list_head(&db->td_salist); sa != NULL; 624 sa = list_next(&db->td_salist, sa)) { 625 mutex_enter(&sa->ts_lock); 626 /* 627 * We don't consider tombstoned or hard expired entries as a 628 * possible match. 629 */ 630 if (sa->ts_tombstoned || EXPIRED(sa, hardexpiretime, now)) { 631 mutex_exit(&sa->ts_lock); 632 continue; 633 } 634 if (tcpsig_sa_match4(sa, src, dst) || 635 tcpsig_sa_match6(sa, src, dst)) { 636 sa->ts_refcnt++; 637 mutex_exit(&sa->ts_lock); 638 break; 639 } 640 mutex_exit(&sa->ts_lock); 641 } 642 643 return (sa); 644 } 645 646 static tcpsig_sa_t * 647 tcpsig_sa_find(struct sockaddr_storage *src, struct sockaddr_storage *dst, 648 tcp_stack_t *tcps) 649 { 650 tcpsig_db_t *db = tcpsig_db(tcps); 651 tcpsig_sa_t *sa; 652 653 rw_enter(&db->td_lock, RW_READER); 654 sa = tcpsig_sa_find_held(src, dst, tcps); 655 rw_exit(&db->td_lock); 656 657 return (sa); 658 } 659 660 static int 661 tcpsig_sa_flush(keysock_t *ks, tcp_stack_t *tcps, int *diagp) 662 { 663 tcpsig_db_t *db = tcpsig_db(tcps); 664 tcpsig_sa_t *nextsa; 665 666 rw_enter(&db->td_lock, RW_WRITER); 667 nextsa = list_head(&db->td_salist); 668 while (nextsa != NULL) { 669 tcpsig_sa_t *sa = nextsa; 670 671 nextsa = list_next(&db->td_salist, sa); 672 673 mutex_enter(&sa->ts_lock); 674 if (sa->ts_refcnt > 0) { 675 sa->ts_tombstoned = true; 676 mutex_exit(&sa->ts_lock); 677 continue; 678 } 679 680 list_remove(&db->td_salist, sa); 681 682 mutex_exit(&sa->ts_lock); 683 tcpsig_sa_free(sa); 684 } 685 686 rw_exit(&db->td_lock); 687 688 return (0); 689 } 690 691 static int 692 tcpsig_sa_add(keysock_t *ks, tcp_stack_t *tcps, keysock_in_t *ksi, 693 sadb_ext_t **extv, int *diagp) 694 { 695 tcpsig_db_t *db; 696 sadb_address_t *srcext, *dstext; 697 sadb_lifetime_t *soft, *hard; 698 sadb_sa_t *assoc; 699 struct sockaddr_storage *src, *dst; 700 sadb_key_t *key; 701 tcpsig_sa_t *sa, *dupsa; 702 int ret = 0; 703 704 assoc = (sadb_sa_t *)extv[SADB_EXT_SA]; 705 srcext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_SRC]; 706 dstext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_DST]; 707 key = (sadb_key_t *)extv[SADB_X_EXT_STR_AUTH]; 708 soft = (sadb_lifetime_t *)extv[SADB_EXT_LIFETIME_SOFT]; 709 hard = (sadb_lifetime_t *)extv[SADB_EXT_LIFETIME_HARD]; 710 711 if (assoc == NULL) { 712 *diagp = SADB_X_DIAGNOSTIC_MISSING_SA; 713 return (EINVAL); 714 } 715 716 if (srcext == NULL) { 717 *diagp = SADB_X_DIAGNOSTIC_MISSING_SRC; 718 return (EINVAL); 719 } 720 721 if (dstext == NULL) { 722 *diagp = SADB_X_DIAGNOSTIC_MISSING_DST; 723 return (EINVAL); 724 } 725 726 if (key == NULL) { 727 *diagp = SADB_X_DIAGNOSTIC_MISSING_ASTR; 728 return (EINVAL); 729 } 730 731 if ((*diagp = tcpsig_check_lifetimes(hard, soft)) != 732 SADB_X_DIAGNOSTIC_NONE) { 733 return (EINVAL); 734 } 735 736 src = (struct sockaddr_storage *)(srcext + 1); 737 dst = (struct sockaddr_storage *)(dstext + 1); 738 739 if (src->ss_family != dst->ss_family) { 740 *diagp = SADB_X_DIAGNOSTIC_AF_MISMATCH; 741 return (EINVAL); 742 } 743 744 if (src->ss_family != AF_INET && src->ss_family != AF_INET6) { 745 *diagp = SADB_X_DIAGNOSTIC_BAD_SRC_AF; 746 return (EINVAL); 747 } 748 749 /* We only support MD5 */ 750 if (assoc->sadb_sa_auth != SADB_AALG_MD5) { 751 *diagp = SADB_X_DIAGNOSTIC_BAD_AALG; 752 return (EINVAL); 753 } 754 755 /* The authentication key length must be a multiple of whole bytes */ 756 if ((key->sadb_key_bits & 0x7) != 0) { 757 *diagp = SADB_X_DIAGNOSTIC_MALFORMED_AKEY; 758 return (EINVAL); 759 } 760 761 db = tcpsig_db(tcps); 762 763 sa = kmem_zalloc(sizeof (*sa), KM_NOSLEEP_LAZY); 764 if (sa == NULL) 765 return (ENOMEM); 766 767 sa->ts_stack = tcps; 768 sa->ts_family = src->ss_family; 769 if (sa->ts_family == AF_INET6) { 770 bcopy(src, (sin6_t *)&sa->ts_src, sizeof (sin6_t)); 771 bcopy(dst, (sin6_t *)&sa->ts_dst, sizeof (sin6_t)); 772 } else { 773 bcopy(src, (sin_t *)&sa->ts_src, sizeof (sin_t)); 774 bcopy(dst, (sin_t *)&sa->ts_dst, sizeof (sin_t)); 775 } 776 777 sa->ts_key.sak_algid = assoc->sadb_sa_auth; 778 sa->ts_key.sak_keylen = SADB_1TO8(key->sadb_key_bits); 779 sa->ts_key.sak_keybits = key->sadb_key_bits; 780 781 sa->ts_key.sak_key = kmem_alloc(sa->ts_key.sak_keylen, 782 KM_NOSLEEP_LAZY); 783 if (sa->ts_key.sak_key == NULL) { 784 kmem_free(sa, sizeof (*sa)); 785 return (ENOMEM); 786 } 787 bcopy(key + 1, sa->ts_key.sak_key, sa->ts_key.sak_keylen); 788 bzero(key + 1, sa->ts_key.sak_keylen); 789 790 mutex_init(&sa->ts_lock, NULL, MUTEX_DEFAULT, NULL); 791 792 sa->ts_state = SADB_SASTATE_MATURE; 793 sa->ts_addtime = gethrestime_sec(); 794 sa->ts_usetime = 0; 795 if (soft != NULL) { 796 sa->ts_softaddlt = soft->sadb_lifetime_addtime; 797 sa->ts_softuselt = soft->sadb_lifetime_usetime; 798 SET_EXPIRE(sa, softaddlt, softexpiretime); 799 } 800 801 if (hard != NULL) { 802 sa->ts_hardaddlt = hard->sadb_lifetime_addtime; 803 sa->ts_harduselt = hard->sadb_lifetime_usetime; 804 SET_EXPIRE(sa, hardaddlt, hardexpiretime); 805 } 806 807 sa->ts_refcnt = 0; 808 sa->ts_tombstoned = false; 809 810 rw_enter(&db->td_lock, RW_WRITER); 811 if ((dupsa = tcpsig_sa_find_held(src, dst, tcps)) != NULL) { 812 rw_exit(&db->td_lock); 813 tcpsig_sa_rele(dupsa); 814 tcpsig_sa_free(sa); 815 *diagp = SADB_X_DIAGNOSTIC_DUPLICATE_SA; 816 ret = EEXIST; 817 } else { 818 list_insert_tail(&db->td_salist, sa); 819 rw_exit(&db->td_lock); 820 } 821 822 return (ret); 823 } 824 825 /* 826 * Handle an UPDATE message. We only support updating lifetimes. 827 */ 828 static int 829 tcpsig_sa_update(keysock_t *ks, tcp_stack_t *tcps, keysock_in_t *ksi, 830 sadb_ext_t **extv, int *diagp) 831 { 832 tcpsig_db_t *db; 833 sadb_address_t *srcext, *dstext; 834 sadb_lifetime_t *soft, *hard; 835 struct sockaddr_storage *src, *dst; 836 tcpsig_sa_t *sa; 837 838 srcext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_SRC]; 839 dstext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_DST]; 840 soft = (sadb_lifetime_t *)extv[SADB_EXT_LIFETIME_SOFT]; 841 hard = (sadb_lifetime_t *)extv[SADB_EXT_LIFETIME_HARD]; 842 843 if (srcext == NULL) { 844 *diagp = SADB_X_DIAGNOSTIC_MISSING_SRC; 845 return (EINVAL); 846 } 847 848 if (dstext == NULL) { 849 *diagp = SADB_X_DIAGNOSTIC_MISSING_DST; 850 return (EINVAL); 851 } 852 853 854 if ((*diagp = tcpsig_check_lifetimes(hard, soft)) != 855 SADB_X_DIAGNOSTIC_NONE) { 856 return (EINVAL); 857 } 858 859 src = (struct sockaddr_storage *)(srcext + 1); 860 dst = (struct sockaddr_storage *)(dstext + 1); 861 862 sa = tcpsig_sa_find(src, dst, tcps); 863 864 if (sa == NULL) { 865 *diagp = SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND; 866 return (ESRCH); 867 } 868 869 tcpsig_update_lifetimes(sa, hard, soft); 870 tcpsig_sa_rele(sa); 871 872 /* 873 * Run an aging pass in case updating the SA lifetimes has resulted in 874 * the SA now being aged out. 875 */ 876 tcpsig_sa_age(ks, tcps); 877 878 return (0); 879 } 880 881 static mblk_t * 882 tcpsig_dump_one(const tcpsig_sa_t *sa, sadb_msg_t *samsg) 883 { 884 size_t alloclen, keysize; 885 sadb_sa_t *assoc; 886 sadb_msg_t *newsamsg; 887 uint8_t *cur, *end; 888 sadb_key_t *key; 889 mblk_t *mp; 890 bool soft = false, hard = false; 891 892 ASSERT(MUTEX_HELD(&sa->ts_lock)); 893 894 alloclen = sizeof (sadb_msg_t) + sizeof (sadb_sa_t) + 895 2 * tcpsig_addr_extsize(sa); 896 897 if (sa->ts_softaddlt != 0 || sa->ts_softuselt != 0) { 898 alloclen += sizeof (sadb_lifetime_t); 899 soft = true; 900 } 901 902 if (sa->ts_hardaddlt != 0 || sa->ts_harduselt != 0) { 903 alloclen += sizeof (sadb_lifetime_t); 904 hard = true; 905 } 906 907 /* Add space for LIFETIME_CURRENT */ 908 if (soft || hard) 909 alloclen += sizeof (sadb_lifetime_t); 910 911 keysize = roundup(sizeof (sadb_key_t) + sa->ts_key.sak_keylen, 912 sizeof (uint64_t)); 913 914 alloclen += keysize; 915 916 mp = allocb(alloclen, BPRI_HI); 917 if (mp == NULL) 918 return (NULL); 919 920 bzero(mp->b_rptr, alloclen); 921 mp->b_wptr += alloclen; 922 end = mp->b_wptr; 923 924 newsamsg = (sadb_msg_t *)mp->b_rptr; 925 *newsamsg = *samsg; 926 newsamsg->sadb_msg_len = (uint16_t)SADB_8TO64(alloclen); 927 928 cur = (uint8_t *)(newsamsg + 1); 929 cur = tcpsig_make_sa_ext(cur, end, sa); 930 cur = tcpsig_make_addr_ext(cur, end, SADB_EXT_ADDRESS_SRC, 931 sa->ts_family, &sa->ts_src); 932 cur = tcpsig_make_addr_ext(cur, end, SADB_EXT_ADDRESS_DST, 933 sa->ts_family, &sa->ts_dst); 934 935 if (cur == NULL) { 936 freeb(mp); 937 return (NULL); 938 } 939 940 if (soft || hard) { 941 sadb_lifetime_t *lt = (sadb_lifetime_t *)cur; 942 943 lt->sadb_lifetime_len = SADB_8TO64(sizeof (*lt)); 944 lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; 945 lt->sadb_lifetime_allocations = 0; 946 lt->sadb_lifetime_bytes = 0; 947 lt->sadb_lifetime_addtime = sa->ts_addtime; 948 lt->sadb_lifetime_usetime = sa->ts_usetime; 949 lt++; 950 951 if (soft) { 952 lt->sadb_lifetime_len = SADB_8TO64(sizeof (*lt)); 953 lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; 954 lt->sadb_lifetime_allocations = 0; 955 lt->sadb_lifetime_bytes = 0; 956 lt->sadb_lifetime_addtime = sa->ts_softaddlt; 957 lt->sadb_lifetime_usetime = sa->ts_softuselt; 958 lt++; 959 } 960 if (hard) { 961 lt->sadb_lifetime_len = SADB_8TO64(sizeof (*lt)); 962 lt->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; 963 lt->sadb_lifetime_allocations = 0; 964 lt->sadb_lifetime_bytes = 0; 965 lt->sadb_lifetime_addtime = sa->ts_hardaddlt; 966 lt->sadb_lifetime_usetime = sa->ts_harduselt; 967 lt++; 968 } 969 970 cur = (uint8_t *)lt; 971 } 972 973 key = (sadb_key_t *)cur; 974 key->sadb_key_exttype = SADB_X_EXT_STR_AUTH; 975 key->sadb_key_len = SADB_8TO64(keysize); 976 key->sadb_key_bits = sa->ts_key.sak_keybits; 977 key->sadb_key_reserved = 0; 978 bcopy(sa->ts_key.sak_key, (uint8_t *)(key + 1), sa->ts_key.sak_keylen); 979 980 return (mp); 981 } 982 983 static int 984 tcpsig_sa_dump(keysock_t *ks, tcp_stack_t *tcps, sadb_msg_t *samsg, int *diag) 985 { 986 tcpsig_db_t *db; 987 tcpsig_sa_t *sa; 988 989 db = tcpsig_db(tcps); 990 rw_enter(&db->td_lock, RW_READER); 991 992 for (sa = list_head(&db->td_salist); sa != NULL; 993 sa = list_next(&db->td_salist, sa)) { 994 mblk_t *mp; 995 996 mutex_enter(&sa->ts_lock); 997 if (sa->ts_tombstoned) { 998 mutex_exit(&sa->ts_lock); 999 continue; 1000 } 1001 mp = tcpsig_dump_one(sa, samsg); 1002 mutex_exit(&sa->ts_lock); 1003 1004 if (mp == NULL) { 1005 rw_exit(&db->td_lock); 1006 return (ENOMEM); 1007 } 1008 keysock_passup(mp, (sadb_msg_t *)mp->b_rptr, 1009 ks->keysock_serial, NULL, B_TRUE, ks->keysock_keystack); 1010 } 1011 1012 rw_exit(&db->td_lock); 1013 1014 /* A sequence number of 0 indicates the end of the list */ 1015 samsg->sadb_msg_seq = 0; 1016 1017 return (0); 1018 } 1019 1020 static int 1021 tcpsig_sa_delget(keysock_t *ks, tcp_stack_t *tcps, sadb_msg_t *samsg, 1022 sadb_ext_t **extv, int *diagp) 1023 { 1024 sadb_address_t *srcext, *dstext; 1025 struct sockaddr_storage *src, *dst; 1026 tcpsig_sa_t *sa; 1027 mblk_t *mp; 1028 1029 srcext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_SRC]; 1030 dstext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_DST]; 1031 1032 if (srcext == NULL) { 1033 *diagp = SADB_X_DIAGNOSTIC_MISSING_SRC; 1034 return (EINVAL); 1035 } 1036 1037 if (dstext == NULL) { 1038 *diagp = SADB_X_DIAGNOSTIC_MISSING_DST; 1039 return (EINVAL); 1040 } 1041 1042 src = (struct sockaddr_storage *)(srcext + 1); 1043 dst = (struct sockaddr_storage *)(dstext + 1); 1044 1045 sa = tcpsig_sa_find(src, dst, tcps); 1046 1047 if (sa == NULL) { 1048 *diagp = SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND; 1049 return (ESRCH); 1050 } 1051 1052 if (samsg->sadb_msg_type == SADB_GET) { 1053 mutex_enter(&sa->ts_lock); 1054 mp = tcpsig_dump_one(sa, samsg); 1055 mutex_exit(&sa->ts_lock); 1056 1057 if (mp == NULL) { 1058 tcpsig_sa_rele(sa); 1059 return (ENOMEM); 1060 } 1061 keysock_passup(mp, (sadb_msg_t *)mp->b_rptr, 1062 ks->keysock_serial, NULL, B_TRUE, ks->keysock_keystack); 1063 tcpsig_sa_rele(sa); 1064 1065 return (0); 1066 } 1067 1068 /* 1069 * Delete the entry. 1070 * At this point we still have a hold on the entry from the find call 1071 * above, so mark it as tombstoned and then release the hold. If 1072 * that causes the reference count to become 0, the entry will be 1073 * removed from the database. 1074 */ 1075 1076 mutex_enter(&sa->ts_lock); 1077 sa->ts_tombstoned = true; 1078 mutex_exit(&sa->ts_lock); 1079 tcpsig_sa_rele(sa); 1080 1081 return (0); 1082 } 1083 1084 void 1085 tcpsig_sa_handler(keysock_t *ks, mblk_t *mp, sadb_msg_t *samsg, 1086 sadb_ext_t **extv) 1087 { 1088 keysock_stack_t *keystack = ks->keysock_keystack; 1089 netstack_t *nst = keystack->keystack_netstack; 1090 tcp_stack_t *tcps = nst->netstack_tcp; 1091 keysock_in_t *ksi = (keysock_in_t *)mp->b_rptr; 1092 int diag = SADB_X_DIAGNOSTIC_NONE; 1093 int error; 1094 1095 tcpsig_sa_age(ks, tcps); 1096 1097 switch (samsg->sadb_msg_type) { 1098 case SADB_ADD: 1099 error = tcpsig_sa_add(ks, tcps, ksi, extv, &diag); 1100 keysock_error(ks, mp, error, diag); 1101 break; 1102 case SADB_UPDATE: 1103 error = tcpsig_sa_update(ks, tcps, ksi, extv, &diag); 1104 keysock_error(ks, mp, error, diag); 1105 break; 1106 case SADB_GET: 1107 case SADB_DELETE: 1108 error = tcpsig_sa_delget(ks, tcps, samsg, extv, &diag); 1109 keysock_error(ks, mp, error, diag); 1110 break; 1111 case SADB_FLUSH: 1112 error = tcpsig_sa_flush(ks, tcps, &diag); 1113 keysock_error(ks, mp, error, diag); 1114 break; 1115 case SADB_DUMP: 1116 error = tcpsig_sa_dump(ks, tcps, samsg, &diag); 1117 keysock_error(ks, mp, error, diag); 1118 break; 1119 default: 1120 keysock_error(ks, mp, EOPNOTSUPP, diag); 1121 break; 1122 } 1123 } 1124 1125 bool 1126 tcpsig_sa_exists(tcp_t *tcp, bool inbound, tcpsig_sa_t **sap) 1127 { 1128 tcp_stack_t *tcps = tcp->tcp_tcps; 1129 conn_t *connp = tcp->tcp_connp; 1130 struct sockaddr_storage src, dst; 1131 tcpsig_sa_t *sa; 1132 1133 bzero(&src, sizeof (src)); 1134 bzero(&dst, sizeof (dst)); 1135 1136 if (connp->conn_ipversion == IPV6_VERSION) { 1137 sin6_t *sin6; 1138 1139 sin6 = (sin6_t *)&src; 1140 sin6->sin6_family = AF_INET6; 1141 if (inbound) { 1142 sin6->sin6_addr = connp->conn_faddr_v6; 1143 sin6->sin6_port = connp->conn_fport; 1144 } else { 1145 sin6->sin6_addr = connp->conn_saddr_v6; 1146 sin6->sin6_port = connp->conn_lport; 1147 } 1148 1149 sin6 = (sin6_t *)&dst; 1150 sin6->sin6_family = AF_INET6; 1151 if (inbound) { 1152 sin6->sin6_addr = connp->conn_saddr_v6; 1153 sin6->sin6_port = connp->conn_lport; 1154 } else { 1155 sin6->sin6_addr = connp->conn_faddr_v6; 1156 sin6->sin6_port = connp->conn_fport; 1157 } 1158 } else { 1159 sin_t *sin; 1160 1161 sin = (sin_t *)&src; 1162 sin->sin_family = AF_INET; 1163 if (inbound) { 1164 sin->sin_addr.s_addr = connp->conn_faddr_v4; 1165 sin->sin_port = connp->conn_fport; 1166 } else { 1167 sin->sin_addr.s_addr = connp->conn_saddr_v4; 1168 sin->sin_port = connp->conn_lport; 1169 } 1170 1171 sin = (sin_t *)&dst; 1172 sin->sin_family = AF_INET; 1173 if (inbound) { 1174 sin->sin_addr.s_addr = connp->conn_saddr_v4; 1175 sin->sin_port = connp->conn_lport; 1176 } else { 1177 sin->sin_addr.s_addr = connp->conn_faddr_v4; 1178 sin->sin_port = connp->conn_fport; 1179 } 1180 } 1181 1182 sa = tcpsig_sa_find(&src, &dst, tcps); 1183 1184 if (sa == NULL) 1185 return (false); 1186 1187 if (sap != NULL) 1188 *sap = sa; 1189 else 1190 tcpsig_sa_rele(sa); 1191 1192 return (true); 1193 } 1194 1195 static void 1196 tcpsig_pseudo_compute4(tcp_t *tcp, int tcplen, MD5_CTX *ctx, bool inbound) 1197 { 1198 struct ip_pseudo { 1199 struct in_addr ipp_src; 1200 struct in_addr ipp_dst; 1201 uint8_t ipp_pad; 1202 uint8_t ipp_proto; 1203 uint16_t ipp_len; 1204 } ipp; 1205 conn_t *connp = tcp->tcp_connp; 1206 1207 if (inbound) { 1208 ipp.ipp_src.s_addr = connp->conn_faddr_v4; 1209 ipp.ipp_dst.s_addr = connp->conn_saddr_v4; 1210 } else { 1211 ipp.ipp_src.s_addr = connp->conn_saddr_v4; 1212 ipp.ipp_dst.s_addr = connp->conn_faddr_v4; 1213 } 1214 ipp.ipp_pad = 0; 1215 ipp.ipp_proto = IPPROTO_TCP; 1216 ipp.ipp_len = htons(tcplen); 1217 1218 DTRACE_PROBE1(ipp4, struct ip_pseudo *, &ipp); 1219 1220 MD5Update(ctx, (char *)&ipp, sizeof (ipp)); 1221 } 1222 1223 static void 1224 tcpsig_pseudo_compute6(tcp_t *tcp, int tcplen, MD5_CTX *ctx, bool inbound) 1225 { 1226 struct ip6_pseudo { 1227 struct in6_addr ipp_src; 1228 struct in6_addr ipp_dst; 1229 uint32_t ipp_len; 1230 uint32_t ipp_nxt; 1231 } ip6p; 1232 conn_t *connp = tcp->tcp_connp; 1233 1234 if (inbound) { 1235 ip6p.ipp_src = connp->conn_faddr_v6; 1236 ip6p.ipp_dst = connp->conn_saddr_v6; 1237 } else { 1238 ip6p.ipp_src = connp->conn_saddr_v6; 1239 ip6p.ipp_dst = connp->conn_faddr_v6; 1240 } 1241 ip6p.ipp_len = htonl(tcplen); 1242 ip6p.ipp_nxt = htonl(IPPROTO_TCP); 1243 1244 DTRACE_PROBE1(ipp6, struct ip6_pseudo *, &ip6p); 1245 1246 MD5Update(ctx, (char *)&ip6p, sizeof (ip6p)); 1247 } 1248 1249 bool 1250 tcpsig_signature(mblk_t *mp, tcp_t *tcp, tcpha_t *tcpha, int tcplen, 1251 uint8_t *digest, bool inbound) 1252 { 1253 tcp_stack_t *tcps = tcp->tcp_tcps; 1254 conn_t *connp = tcp->tcp_connp; 1255 tcpsig_sa_t *sa; 1256 MD5_CTX context; 1257 1258 /* 1259 * The TCP_MD5SIG option is 20 bytes, including padding, which adds 5 1260 * 32-bit words to the header's 4-bit field. Check that it can fit in 1261 * the current packet. 1262 */ 1263 if (!inbound && (tcpha->tha_offset_and_reserved >> 4) > 10) { 1264 TCP_STAT(tcps, tcp_sig_no_space); 1265 return (false); 1266 } 1267 1268 sa = inbound ? tcp->tcp_sig_sa_in : tcp->tcp_sig_sa_out; 1269 if (sa == NULL) { 1270 if (!tcpsig_sa_exists(tcp, inbound, &sa)) { 1271 TCP_STAT(tcps, tcp_sig_match_failed); 1272 return (false); 1273 } 1274 1275 /* 1276 * tcpsig_sa_exists() returns a held SA, so we don't need to 1277 * take another hold before adding it to tcp. 1278 */ 1279 if (inbound) 1280 tcp->tcp_sig_sa_in = sa; 1281 else 1282 tcp->tcp_sig_sa_out = sa; 1283 } 1284 1285 tcpsig_sa_touch(sa); 1286 1287 VERIFY3U(sa->ts_key.sak_algid, ==, SADB_AALG_MD5); 1288 1289 /* We have a key for this connection, generate the hash */ 1290 MD5Init(&context); 1291 1292 /* TCP pseudo-header */ 1293 if (connp->conn_ipversion == IPV6_VERSION) 1294 tcpsig_pseudo_compute6(tcp, tcplen, &context, inbound); 1295 else 1296 tcpsig_pseudo_compute4(tcp, tcplen, &context, inbound); 1297 1298 /* TCP header, excluding options and with a zero checksum */ 1299 uint16_t offset = tcpha->tha_offset_and_reserved; 1300 uint16_t sum = tcpha->tha_sum; 1301 1302 if (!inbound) { 1303 /* Account for the MD5 option we are going to add */ 1304 tcpha->tha_offset_and_reserved += (5 << 4); 1305 } 1306 tcpha->tha_sum = 0; 1307 MD5Update(&context, tcpha, sizeof (*tcpha)); 1308 tcpha->tha_offset_and_reserved = offset; 1309 tcpha->tha_sum = sum; 1310 1311 /* TCP segment data */ 1312 for (; mp != NULL; mp = mp->b_cont) 1313 MD5Update(&context, mp->b_rptr, mp->b_wptr - mp->b_rptr); 1314 1315 /* Connection-specific key */ 1316 MD5Update(&context, sa->ts_key.sak_key, sa->ts_key.sak_keylen); 1317 1318 MD5Final(digest, &context); 1319 1320 return (true); 1321 } 1322 1323 bool 1324 tcpsig_verify(mblk_t *mp, tcp_t *tcp, tcpha_t *tcpha, ip_recv_attr_t *ira, 1325 uint8_t *digest) 1326 { 1327 uint8_t calc_digest[MD5_DIGEST_LENGTH]; 1328 1329 if (!tcpsig_signature(mp, tcp, tcpha, 1330 ira->ira_pktlen - ira->ira_ip_hdr_length, calc_digest, true)) { 1331 /* The appropriate stat will already have been bumped */ 1332 return (false); 1333 } 1334 1335 if (bcmp(digest, calc_digest, sizeof (calc_digest)) != 0) { 1336 TCP_STAT(tcp->tcp_tcps, tcp_sig_verify_failed); 1337 return (false); 1338 } 1339 1340 return (true); 1341 } 1342