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
tcpsig_init(tcp_stack_t * tcps)108 tcpsig_init(tcp_stack_t *tcps)
109 {
110 mutex_init(&tcps->tcps_sigdb_lock, NULL, MUTEX_DEFAULT, NULL);
111 }
112
113 void
tcpsig_fini(tcp_stack_t * tcps)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 *
tcpsig_db(tcp_stack_t * tcps)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 void
tcpsig_sa_free(tcpsig_sa_t * sa)150 tcpsig_sa_free(tcpsig_sa_t *sa)
151 {
152 ASSERT0(sa->ts_refcnt);
153 mutex_destroy(&sa->ts_lock);
154 kmem_free(sa->ts_key.sak_key, sa->ts_key.sak_keylen);
155 kmem_free(sa, sizeof (*sa));
156 }
157
158 void
tcpsig_sa_rele(tcpsig_sa_t * sa)159 tcpsig_sa_rele(tcpsig_sa_t *sa)
160 {
161 mutex_enter(&sa->ts_lock);
162 VERIFY3U(sa->ts_refcnt, >, 0);
163 sa->ts_refcnt--;
164 /*
165 * If we are tombstoned (have been marked as deleted) and the reference
166 * count has now dropped to zero, then we can go ahead and finally
167 * remove this SA from the database.
168 */
169 if (sa->ts_tombstoned && sa->ts_refcnt == 0) {
170 tcpsig_db_t *db = tcpsig_db(sa->ts_stack);
171
172 /*
173 * To maintain the required lock ordering, we need to drop the
174 * lock on the SA while acquiring the RW lock on the list. Take
175 * an additional hold before doing this dance and drop it once
176 * we have re-gained the lock.
177 */
178 sa->ts_refcnt++;
179 mutex_exit(&sa->ts_lock);
180 rw_enter(&db->td_lock, RW_WRITER);
181 mutex_enter(&sa->ts_lock);
182 sa->ts_refcnt--;
183 mutex_exit(&sa->ts_lock);
184
185 list_remove(&db->td_salist, sa);
186
187 rw_exit(&db->td_lock);
188 tcpsig_sa_free(sa);
189 } else {
190 mutex_exit(&sa->ts_lock);
191 }
192 }
193
194 static bool
tcpsig_sa_match4(tcpsig_sa_t * sa,struct sockaddr_storage * src_s,struct sockaddr_storage * dst_s)195 tcpsig_sa_match4(tcpsig_sa_t *sa, struct sockaddr_storage *src_s,
196 struct sockaddr_storage *dst_s)
197 {
198 sin_t msrc, mdst, *src, *dst, *sasrc, *sadst;
199
200 if (src_s->ss_family != AF_INET)
201 return (false);
202
203 src = (sin_t *)src_s;
204 dst = (sin_t *)dst_s;
205
206 if (sa->ts_family == AF_INET6) {
207 sin6_t *sasrc6 = (sin6_t *)&sa->ts_src;
208 sin6_t *sadst6 = (sin6_t *)&sa->ts_dst;
209
210 if (!IN6_IS_ADDR_V4MAPPED(&sasrc6->sin6_addr) ||
211 !IN6_IS_ADDR_V4MAPPED(&sadst6->sin6_addr)) {
212 return (false);
213 }
214
215 msrc = sin_null;
216 msrc.sin_family = AF_INET;
217 msrc.sin_port = sasrc6->sin6_port;
218 IN6_V4MAPPED_TO_INADDR(&sasrc6->sin6_addr, &msrc.sin_addr);
219 sasrc = &msrc;
220
221 mdst = sin_null;
222 mdst.sin_family = AF_INET;
223 mdst.sin_port = sadst6->sin6_port;
224 IN6_V4MAPPED_TO_INADDR(&sadst6->sin6_addr, &mdst.sin_addr);
225 sadst = &mdst;
226 } else {
227 sasrc = (sin_t *)&sa->ts_src;
228 sadst = (sin_t *)&sa->ts_dst;
229 }
230
231 if (sasrc->sin_port != 0 && sasrc->sin_port != src->sin_port)
232 return (false);
233 if (sadst->sin_port != 0 && sadst->sin_port != dst->sin_port)
234 return (false);
235
236 if (sasrc->sin_addr.s_addr != src->sin_addr.s_addr)
237 return (false);
238 if (sadst->sin_addr.s_addr != dst->sin_addr.s_addr)
239 return (false);
240
241 return (true);
242 }
243
244 static bool
tcpsig_sa_match6(tcpsig_sa_t * sa,struct sockaddr_storage * src_s,struct sockaddr_storage * dst_s)245 tcpsig_sa_match6(tcpsig_sa_t *sa, struct sockaddr_storage *src_s,
246 struct sockaddr_storage *dst_s)
247 {
248 sin6_t *src, *dst, *sasrc, *sadst;
249
250 if (src_s->ss_family != AF_INET6 || sa->ts_src.ss_family != AF_INET6)
251 return (false);
252
253 src = (sin6_t *)src_s;
254 dst = (sin6_t *)dst_s;
255
256 sasrc = (sin6_t *)&sa->ts_src;
257 sadst = (sin6_t *)&sa->ts_dst;
258
259 if (sasrc->sin6_port != 0 && sasrc->sin6_port != src->sin6_port)
260 return (false);
261 if (sadst->sin6_port != 0 && sadst->sin6_port != dst->sin6_port)
262 return (false);
263
264 if (!IN6_ARE_ADDR_EQUAL(&sasrc->sin6_addr, &src->sin6_addr))
265 return (false);
266 if (!IN6_ARE_ADDR_EQUAL(&sadst->sin6_addr, &dst->sin6_addr))
267 return (false);
268
269 return (true);
270 }
271
272 static tcpsig_sa_t *
tcpsig_sa_find_held(struct sockaddr_storage * src,struct sockaddr_storage * dst,tcp_stack_t * tcps)273 tcpsig_sa_find_held(struct sockaddr_storage *src, struct sockaddr_storage *dst,
274 tcp_stack_t *tcps)
275 {
276 tcpsig_db_t *db = tcpsig_db(tcps);
277 tcpsig_sa_t *sa = NULL;
278
279 ASSERT(RW_LOCK_HELD(&db->td_lock));
280
281 if (src->ss_family != dst->ss_family)
282 return (NULL);
283
284 for (sa = list_head(&db->td_salist); sa != NULL;
285 sa = list_next(&db->td_salist, sa)) {
286 mutex_enter(&sa->ts_lock);
287 /* We don't consider tombstoned entries as a possible match */
288 if (sa->ts_tombstoned) {
289 mutex_exit(&sa->ts_lock);
290 continue;
291 }
292 if (tcpsig_sa_match4(sa, src, dst) ||
293 tcpsig_sa_match6(sa, src, dst)) {
294 sa->ts_refcnt++;
295 mutex_exit(&sa->ts_lock);
296 break;
297 }
298 mutex_exit(&sa->ts_lock);
299 }
300
301 return (sa);
302 }
303
304 static tcpsig_sa_t *
tcpsig_sa_find(struct sockaddr_storage * src,struct sockaddr_storage * dst,tcp_stack_t * tcps)305 tcpsig_sa_find(struct sockaddr_storage *src, struct sockaddr_storage *dst,
306 tcp_stack_t *tcps)
307 {
308 tcpsig_db_t *db = tcpsig_db(tcps);
309 tcpsig_sa_t *sa;
310
311 rw_enter(&db->td_lock, RW_READER);
312 sa = tcpsig_sa_find_held(src, dst, tcps);
313 rw_exit(&db->td_lock);
314
315 return (sa);
316 }
317
318 static int
tcpsig_sa_flush(keysock_t * ks,tcp_stack_t * tcps,int * diagp)319 tcpsig_sa_flush(keysock_t *ks, tcp_stack_t *tcps, int *diagp)
320 {
321 tcpsig_db_t *db = tcpsig_db(tcps);
322 tcpsig_sa_t *nextsa;
323
324 rw_enter(&db->td_lock, RW_WRITER);
325 nextsa = list_head(&db->td_salist);
326 while (nextsa != NULL) {
327 tcpsig_sa_t *sa = nextsa;
328
329 nextsa = list_next(&db->td_salist, sa);
330
331 mutex_enter(&sa->ts_lock);
332 if (sa->ts_refcnt > 0) {
333 sa->ts_tombstoned = true;
334 mutex_exit(&sa->ts_lock);
335 continue;
336 }
337
338 list_remove(&db->td_salist, sa);
339
340 mutex_exit(&sa->ts_lock);
341 tcpsig_sa_free(sa);
342 }
343
344 rw_exit(&db->td_lock);
345
346 return (0);
347 }
348
349 static int
tcpsig_sa_add(keysock_t * ks,tcp_stack_t * tcps,keysock_in_t * ksi,sadb_ext_t ** extv,int * diagp)350 tcpsig_sa_add(keysock_t *ks, tcp_stack_t *tcps, keysock_in_t *ksi,
351 sadb_ext_t **extv, int *diagp)
352 {
353 tcpsig_db_t *db;
354 sadb_address_t *srcext, *dstext;
355 sadb_sa_t *assoc;
356 struct sockaddr_storage *src, *dst;
357 sadb_key_t *key;
358 tcpsig_sa_t *sa, *dupsa;
359 int ret = 0;
360
361 assoc = (sadb_sa_t *)extv[SADB_EXT_SA];
362 srcext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_SRC];
363 dstext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_DST];
364 key = (sadb_key_t *)extv[SADB_X_EXT_STR_AUTH];
365
366 if (assoc == NULL) {
367 *diagp = SADB_X_DIAGNOSTIC_MISSING_SA;
368 return (EINVAL);
369 }
370
371 if (srcext == NULL) {
372 *diagp = SADB_X_DIAGNOSTIC_MISSING_SRC;
373 return (EINVAL);
374 }
375
376 if (dstext == NULL) {
377 *diagp = SADB_X_DIAGNOSTIC_MISSING_DST;
378 return (EINVAL);
379 }
380
381 if (key == NULL) {
382 *diagp = SADB_X_DIAGNOSTIC_MISSING_ASTR;
383 return (EINVAL);
384 }
385
386 src = (struct sockaddr_storage *)(srcext + 1);
387 dst = (struct sockaddr_storage *)(dstext + 1);
388
389 if (src->ss_family != dst->ss_family) {
390 *diagp = SADB_X_DIAGNOSTIC_AF_MISMATCH;
391 return (EINVAL);
392 }
393
394 if (src->ss_family != AF_INET && src->ss_family != AF_INET6) {
395 *diagp = SADB_X_DIAGNOSTIC_BAD_SRC_AF;
396 return (EINVAL);
397 }
398
399 /* We only support MD5 */
400 if (assoc->sadb_sa_auth != SADB_AALG_MD5) {
401 *diagp = SADB_X_DIAGNOSTIC_BAD_AALG;
402 return (EINVAL);
403 }
404
405 /* The authentication key length must be a multiple of whole bytes */
406 if ((key->sadb_key_bits & 0x7) != 0) {
407 *diagp = SADB_X_DIAGNOSTIC_MALFORMED_AKEY;
408 return (EINVAL);
409 }
410
411 db = tcpsig_db(tcps);
412
413 sa = kmem_zalloc(sizeof (*sa), KM_NOSLEEP_LAZY);
414 if (sa == NULL)
415 return (ENOMEM);
416
417 sa->ts_stack = tcps;
418 sa->ts_family = src->ss_family;
419 if (sa->ts_family == AF_INET6) {
420 bcopy(src, (sin6_t *)&sa->ts_src, sizeof (sin6_t));
421 bcopy(dst, (sin6_t *)&sa->ts_dst, sizeof (sin6_t));
422 } else {
423 bcopy(src, (sin_t *)&sa->ts_src, sizeof (sin_t));
424 bcopy(dst, (sin_t *)&sa->ts_dst, sizeof (sin_t));
425 }
426
427 sa->ts_key.sak_algid = assoc->sadb_sa_auth;
428 sa->ts_key.sak_keylen = SADB_1TO8(key->sadb_key_bits);
429 sa->ts_key.sak_keybits = key->sadb_key_bits;
430
431 sa->ts_key.sak_key = kmem_alloc(sa->ts_key.sak_keylen,
432 KM_NOSLEEP_LAZY);
433 if (sa->ts_key.sak_key == NULL) {
434 kmem_free(sa, sizeof (*sa));
435 return (ENOMEM);
436 }
437 bcopy(key + 1, sa->ts_key.sak_key, sa->ts_key.sak_keylen);
438 bzero(key + 1, sa->ts_key.sak_keylen);
439
440 mutex_init(&sa->ts_lock, NULL, MUTEX_DEFAULT, NULL);
441 sa->ts_refcnt = 0;
442 sa->ts_tombstoned = false;
443
444 rw_enter(&db->td_lock, RW_WRITER);
445 if ((dupsa = tcpsig_sa_find_held(src, dst, tcps)) != NULL) {
446 rw_exit(&db->td_lock);
447 tcpsig_sa_rele(dupsa);
448 tcpsig_sa_free(sa);
449 *diagp = SADB_X_DIAGNOSTIC_DUPLICATE_SA;
450 ret = EEXIST;
451 } else {
452 list_insert_tail(&db->td_salist, sa);
453 rw_exit(&db->td_lock);
454 }
455
456 return (ret);
457 }
458
459 static uint8_t *
tcpsig_make_addr_ext(uint8_t * start,uint8_t * end,uint16_t exttype,sa_family_t af,struct sockaddr_storage * addr)460 tcpsig_make_addr_ext(uint8_t *start, uint8_t *end, uint16_t exttype,
461 sa_family_t af, struct sockaddr_storage *addr)
462 {
463 uint8_t *cur = start;
464 unsigned int addrext_len;
465 sadb_address_t *addrext = (sadb_address_t *)cur;
466
467 if (cur == NULL)
468 return (NULL);
469
470 cur += sizeof (*addrext);
471 if (cur > end)
472 return (NULL);
473
474 addrext->sadb_address_proto = IPPROTO_TCP;
475 addrext->sadb_address_reserved = 0;
476 addrext->sadb_address_prefixlen = 0;
477 addrext->sadb_address_exttype = exttype;
478
479 ASSERT(af == AF_INET || af == AF_INET6);
480 if (af == AF_INET) {
481 sin_t *sin = (sin_t *)cur;
482
483 cur += sizeof (*sin);
484 if (cur > end)
485 return (NULL);
486
487 *sin = sin_null;
488 bcopy(addr, sin, sizeof (*sin));
489 } else {
490 sin6_t *sin6 = (sin6_t *)cur;
491
492 cur += sizeof (*sin6);
493 if (cur > end)
494 return (NULL);
495
496 *sin6 = sin6_null;
497 bcopy(addr, sin6, sizeof (*sin6));
498 }
499
500 addrext_len = roundup(cur - start, sizeof (uint64_t));
501 addrext->sadb_address_len = SADB_8TO64(addrext_len);
502
503 cur = start + addrext_len;
504 if (cur > end)
505 cur = NULL;
506
507 return (cur);
508 }
509
510 static mblk_t *
tcpsig_dump_one(tcpsig_sa_t * sa,sadb_msg_t * samsg)511 tcpsig_dump_one(tcpsig_sa_t *sa, sadb_msg_t *samsg)
512 {
513 size_t alloclen, addrsize, keysize;
514 sadb_sa_t *assoc;
515 sadb_msg_t *newsamsg;
516 uint8_t *cur, *end;
517 sadb_key_t *key;
518 mblk_t *mp;
519
520 alloclen = sizeof (sadb_msg_t) + sizeof (sadb_sa_t);
521
522 switch (sa->ts_family) {
523 case AF_INET:
524 addrsize = roundup(sizeof (sin_t) +
525 sizeof (sadb_address_t), sizeof (uint64_t));
526 break;
527 case AF_INET6:
528 addrsize = roundup(sizeof (sin6_t) +
529 sizeof (sadb_address_t), sizeof (uint64_t));
530 break;
531 }
532 keysize = roundup(sizeof (sadb_key_t) + sa->ts_key.sak_keylen,
533 sizeof (uint64_t));
534
535 alloclen += addrsize * 2 + keysize;
536
537 mp = allocb(alloclen, BPRI_HI);
538 if (mp == NULL)
539 return (NULL);
540
541 bzero(mp->b_rptr, alloclen);
542 mp->b_wptr += alloclen;
543 end = mp->b_wptr;
544
545 newsamsg = (sadb_msg_t *)mp->b_rptr;
546 *newsamsg = *samsg;
547 newsamsg->sadb_msg_len = (uint16_t)SADB_8TO64(alloclen);
548
549 assoc = (sadb_sa_t *)(newsamsg + 1);
550 assoc->sadb_sa_exttype = SADB_EXT_SA;
551 assoc->sadb_sa_len = SADB_8TO64(sizeof (*assoc));
552 assoc->sadb_sa_auth = sa->ts_key.sak_algid;
553 assoc->sadb_sa_flags = SADB_X_SAFLAGS_TCPSIG;
554 assoc->sadb_sa_state = IPSA_STATE_MATURE;
555
556 cur = (uint8_t *)(assoc + 1);
557 cur = tcpsig_make_addr_ext(cur, end, SADB_EXT_ADDRESS_SRC,
558 sa->ts_family, &sa->ts_src);
559 cur = tcpsig_make_addr_ext(cur, end, SADB_EXT_ADDRESS_DST,
560 sa->ts_family, &sa->ts_dst);
561
562 if (cur == NULL)
563 return (NULL);
564
565 key = (sadb_key_t *)cur;
566 key->sadb_key_exttype = SADB_X_EXT_STR_AUTH;
567 key->sadb_key_len = SADB_8TO64(keysize);
568 key->sadb_key_bits = sa->ts_key.sak_keybits;
569 key->sadb_key_reserved = 0;
570 bcopy(sa->ts_key.sak_key, (uint8_t *)(key + 1), sa->ts_key.sak_keylen);
571
572 return (mp);
573 }
574
575 static int
tcpsig_sa_dump(keysock_t * ks,tcp_stack_t * tcps,sadb_msg_t * samsg,int * diag)576 tcpsig_sa_dump(keysock_t *ks, tcp_stack_t *tcps, sadb_msg_t *samsg, int *diag)
577 {
578 tcpsig_db_t *db;
579 tcpsig_sa_t *sa;
580
581 db = tcpsig_db(tcps);
582 rw_enter(&db->td_lock, RW_READER);
583
584 for (sa = list_head(&db->td_salist); sa != NULL;
585 sa = list_next(&db->td_salist, sa)) {
586 mblk_t *mp;
587
588 mutex_enter(&sa->ts_lock);
589 if (sa->ts_tombstoned) {
590 mutex_exit(&sa->ts_lock);
591 continue;
592 }
593 mutex_exit(&sa->ts_lock);
594
595 mp = tcpsig_dump_one(sa, samsg);
596 if (mp == NULL) {
597 rw_exit(&db->td_lock);
598 return (ENOMEM);
599 }
600 keysock_passup(mp, (sadb_msg_t *)mp->b_rptr,
601 ks->keysock_serial, NULL, B_TRUE, ks->keysock_keystack);
602 }
603
604 rw_exit(&db->td_lock);
605
606 /* A sequence number of 0 indicates the end of the list */
607 samsg->sadb_msg_seq = 0;
608
609 return (0);
610 }
611
612 static int
tcpsig_sa_delget(keysock_t * ks,tcp_stack_t * tcps,sadb_msg_t * samsg,sadb_ext_t ** extv,int * diagp)613 tcpsig_sa_delget(keysock_t *ks, tcp_stack_t *tcps, sadb_msg_t *samsg,
614 sadb_ext_t **extv, int *diagp)
615 {
616 sadb_address_t *srcext, *dstext;
617 struct sockaddr_storage *src, *dst;
618 tcpsig_sa_t *sa;
619 mblk_t *mp;
620
621 srcext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_SRC];
622 dstext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_DST];
623
624 if (srcext == NULL) {
625 *diagp = SADB_X_DIAGNOSTIC_MISSING_SRC;
626 return (EINVAL);
627 }
628
629 if (dstext == NULL) {
630 *diagp = SADB_X_DIAGNOSTIC_MISSING_DST;
631 return (EINVAL);
632 }
633
634 src = (struct sockaddr_storage *)(srcext + 1);
635 dst = (struct sockaddr_storage *)(dstext + 1);
636
637 sa = tcpsig_sa_find(src, dst, tcps);
638
639 if (sa == NULL) {
640 *diagp = SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND;
641 return (ESRCH);
642 }
643
644 if (samsg->sadb_msg_type == SADB_GET) {
645 mp = tcpsig_dump_one(sa, samsg);
646
647 if (mp == NULL)
648 return (ENOMEM);
649 keysock_passup(mp, (sadb_msg_t *)mp->b_rptr,
650 ks->keysock_serial, NULL, B_TRUE, ks->keysock_keystack);
651 tcpsig_sa_rele(sa);
652
653 return (0);
654 }
655
656 /*
657 * Delete the entry.
658 * At this point we still have a hold on the entry from the find call
659 * above, so mark it as tombstoned and then release the hold. If
660 * that causes the reference count to become 0, the entry will be
661 * removed from the database.
662 */
663
664 mutex_enter(&sa->ts_lock);
665 sa->ts_tombstoned = true;
666 mutex_exit(&sa->ts_lock);
667 tcpsig_sa_rele(sa);
668
669 return (0);
670 }
671
672 void
tcpsig_sa_handler(keysock_t * ks,mblk_t * mp,sadb_msg_t * samsg,sadb_ext_t ** extv)673 tcpsig_sa_handler(keysock_t *ks, mblk_t *mp, sadb_msg_t *samsg,
674 sadb_ext_t **extv)
675 {
676 keysock_stack_t *keystack = ks->keysock_keystack;
677 netstack_t *nst = keystack->keystack_netstack;
678 tcp_stack_t *tcps = nst->netstack_tcp;
679 keysock_in_t *ksi = (keysock_in_t *)mp->b_rptr;
680 int diag = SADB_X_DIAGNOSTIC_NONE;
681 int error;
682
683 switch (samsg->sadb_msg_type) {
684 case SADB_ADD:
685 error = tcpsig_sa_add(ks, tcps, ksi, extv, &diag);
686 keysock_error(ks, mp, error, diag);
687 break;
688 case SADB_GET:
689 case SADB_DELETE:
690 error = tcpsig_sa_delget(ks, tcps, samsg, extv, &diag);
691 keysock_error(ks, mp, error, diag);
692 break;
693 case SADB_FLUSH:
694 error = tcpsig_sa_flush(ks, tcps, &diag);
695 keysock_error(ks, mp, error, diag);
696 break;
697 case SADB_DUMP:
698 error = tcpsig_sa_dump(ks, tcps, samsg, &diag);
699 keysock_error(ks, mp, error, diag);
700 break;
701 default:
702 keysock_error(ks, mp, EOPNOTSUPP, diag);
703 break;
704 }
705 }
706
707 bool
tcpsig_sa_exists(tcp_t * tcp,bool inbound,tcpsig_sa_t ** sap)708 tcpsig_sa_exists(tcp_t *tcp, bool inbound, tcpsig_sa_t **sap)
709 {
710 tcp_stack_t *tcps = tcp->tcp_tcps;
711 conn_t *connp = tcp->tcp_connp;
712 struct sockaddr_storage src, dst;
713 tcpsig_sa_t *sa;
714
715 bzero(&src, sizeof (src));
716 bzero(&dst, sizeof (dst));
717
718 if (connp->conn_ipversion == IPV6_VERSION) {
719 sin6_t *sin6;
720
721 sin6 = (sin6_t *)&src;
722 sin6->sin6_family = AF_INET6;
723 if (inbound) {
724 sin6->sin6_addr = connp->conn_faddr_v6;
725 sin6->sin6_port = connp->conn_fport;
726 } else {
727 sin6->sin6_addr = connp->conn_saddr_v6;
728 sin6->sin6_port = connp->conn_lport;
729 }
730
731 sin6 = (sin6_t *)&dst;
732 sin6->sin6_family = AF_INET6;
733 if (inbound) {
734 sin6->sin6_addr = connp->conn_saddr_v6;
735 sin6->sin6_port = connp->conn_lport;
736 } else {
737 sin6->sin6_addr = connp->conn_faddr_v6;
738 sin6->sin6_port = connp->conn_fport;
739 }
740 } else {
741 sin_t *sin;
742
743 sin = (sin_t *)&src;
744 sin->sin_family = AF_INET;
745 if (inbound) {
746 sin->sin_addr.s_addr = connp->conn_faddr_v4;
747 sin->sin_port = connp->conn_fport;
748 } else {
749 sin->sin_addr.s_addr = connp->conn_saddr_v4;
750 sin->sin_port = connp->conn_lport;
751 }
752
753 sin = (sin_t *)&dst;
754 sin->sin_family = AF_INET;
755 if (inbound) {
756 sin->sin_addr.s_addr = connp->conn_saddr_v4;
757 sin->sin_port = connp->conn_lport;
758 } else {
759 sin->sin_addr.s_addr = connp->conn_faddr_v4;
760 sin->sin_port = connp->conn_fport;
761 }
762 }
763
764 sa = tcpsig_sa_find(&src, &dst, tcps);
765
766 if (sa == NULL)
767 return (false);
768
769 if (sap != NULL)
770 *sap = sa;
771 else
772 tcpsig_sa_rele(sa);
773
774 return (true);
775 }
776
777 static void
tcpsig_pseudo_compute4(tcp_t * tcp,int tcplen,MD5_CTX * ctx,bool inbound)778 tcpsig_pseudo_compute4(tcp_t *tcp, int tcplen, MD5_CTX *ctx, bool inbound)
779 {
780 struct ip_pseudo {
781 struct in_addr ipp_src;
782 struct in_addr ipp_dst;
783 uint8_t ipp_pad;
784 uint8_t ipp_proto;
785 uint16_t ipp_len;
786 } ipp;
787 conn_t *connp = tcp->tcp_connp;
788
789 if (inbound) {
790 ipp.ipp_src.s_addr = connp->conn_faddr_v4;
791 ipp.ipp_dst.s_addr = connp->conn_saddr_v4;
792 } else {
793 ipp.ipp_src.s_addr = connp->conn_saddr_v4;
794 ipp.ipp_dst.s_addr = connp->conn_faddr_v4;
795 }
796 ipp.ipp_pad = 0;
797 ipp.ipp_proto = IPPROTO_TCP;
798 ipp.ipp_len = htons(tcplen);
799
800 DTRACE_PROBE1(ipp4, struct ip_pseudo *, &ipp);
801
802 MD5Update(ctx, (char *)&ipp, sizeof (ipp));
803 }
804
805 static void
tcpsig_pseudo_compute6(tcp_t * tcp,int tcplen,MD5_CTX * ctx,bool inbound)806 tcpsig_pseudo_compute6(tcp_t *tcp, int tcplen, MD5_CTX *ctx, bool inbound)
807 {
808 struct ip6_pseudo {
809 struct in6_addr ipp_src;
810 struct in6_addr ipp_dst;
811 uint32_t ipp_len;
812 uint32_t ipp_nxt;
813 } ip6p;
814 conn_t *connp = tcp->tcp_connp;
815
816 if (inbound) {
817 ip6p.ipp_src = connp->conn_faddr_v6;
818 ip6p.ipp_dst = connp->conn_saddr_v6;
819 } else {
820 ip6p.ipp_src = connp->conn_saddr_v6;
821 ip6p.ipp_dst = connp->conn_faddr_v6;
822 }
823 ip6p.ipp_len = htonl(tcplen);
824 ip6p.ipp_nxt = htonl(IPPROTO_TCP);
825
826 DTRACE_PROBE1(ipp6, struct ip6_pseudo *, &ip6p);
827
828 MD5Update(ctx, (char *)&ip6p, sizeof (ip6p));
829 }
830
831 bool
tcpsig_signature(mblk_t * mp,tcp_t * tcp,tcpha_t * tcpha,int tcplen,uint8_t * digest,bool inbound)832 tcpsig_signature(mblk_t *mp, tcp_t *tcp, tcpha_t *tcpha, int tcplen,
833 uint8_t *digest, bool inbound)
834 {
835 tcp_stack_t *tcps = tcp->tcp_tcps;
836 conn_t *connp = tcp->tcp_connp;
837 tcpsig_sa_t *sa;
838 MD5_CTX context;
839
840 /*
841 * The TCP_MD5SIG option is 20 bytes, including padding, which adds 5
842 * 32-bit words to the header's 4-bit field. Check that it can fit in
843 * the current packet.
844 */
845 if (!inbound && (tcpha->tha_offset_and_reserved >> 4) > 10) {
846 TCP_STAT(tcps, tcp_sig_no_space);
847 return (false);
848 }
849
850 sa = inbound ? tcp->tcp_sig_sa_in : tcp->tcp_sig_sa_out;
851 if (sa == NULL) {
852 if (!tcpsig_sa_exists(tcp, inbound, &sa)) {
853 TCP_STAT(tcps, tcp_sig_match_failed);
854 return (false);
855 }
856
857 /*
858 * tcpsig_sa_exists() returns a held SA, so we don't need to
859 * take another hold before adding it to tcp.
860 */
861 if (inbound)
862 tcp->tcp_sig_sa_in = sa;
863 else
864 tcp->tcp_sig_sa_out = sa;
865 }
866
867 VERIFY3U(sa->ts_key.sak_algid, ==, SADB_AALG_MD5);
868
869 /* We have a key for this connection, generate the hash */
870 MD5Init(&context);
871
872 /* TCP pseudo-header */
873 if (connp->conn_ipversion == IPV6_VERSION)
874 tcpsig_pseudo_compute6(tcp, tcplen, &context, inbound);
875 else
876 tcpsig_pseudo_compute4(tcp, tcplen, &context, inbound);
877
878 /* TCP header, excluding options and with a zero checksum */
879 uint16_t offset = tcpha->tha_offset_and_reserved;
880 uint16_t sum = tcpha->tha_sum;
881
882 if (!inbound) {
883 /* Account for the MD5 option we are going to add */
884 tcpha->tha_offset_and_reserved += (5 << 4);
885 }
886 tcpha->tha_sum = 0;
887 MD5Update(&context, tcpha, sizeof (*tcpha));
888 tcpha->tha_offset_and_reserved = offset;
889 tcpha->tha_sum = sum;
890
891 /* TCP segment data */
892 for (; mp != NULL; mp = mp->b_cont)
893 MD5Update(&context, mp->b_rptr, mp->b_wptr - mp->b_rptr);
894
895 /* Connection-specific key */
896 MD5Update(&context, sa->ts_key.sak_key, sa->ts_key.sak_keylen);
897
898 MD5Final(digest, &context);
899
900 return (true);
901 }
902
903 bool
tcpsig_verify(mblk_t * mp,tcp_t * tcp,tcpha_t * tcpha,ip_recv_attr_t * ira,uint8_t * digest)904 tcpsig_verify(mblk_t *mp, tcp_t *tcp, tcpha_t *tcpha, ip_recv_attr_t *ira,
905 uint8_t *digest)
906 {
907 uint8_t calc_digest[MD5_DIGEST_LENGTH];
908
909 if (!tcpsig_signature(mp, tcp, tcpha,
910 ira->ira_pktlen - ira->ira_ip_hdr_length, calc_digest, true)) {
911 /* The appropriate stat will already have been bumped */
912 return (false);
913 }
914
915 if (bcmp(digest, calc_digest, sizeof (calc_digest)) != 0) {
916 TCP_STAT(tcp->tcp_tcps, tcp_sig_verify_failed);
917 return (false);
918 }
919
920 return (true);
921 }
922