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 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2016 by Delphix. All rights reserved.
25 */
26
27 /*
28 * IPsec Security Policy Database.
29 *
30 * This module maintains the SPD and provides routines used by ip and ip6
31 * to apply IPsec policy to inbound and outbound datagrams.
32 */
33
34 #include <sys/types.h>
35 #include <sys/stream.h>
36 #include <sys/stropts.h>
37 #include <sys/sysmacros.h>
38 #include <sys/strsubr.h>
39 #include <sys/strsun.h>
40 #include <sys/strlog.h>
41 #include <sys/strsun.h>
42 #include <sys/cmn_err.h>
43 #include <sys/zone.h>
44
396 /*
397 * Globals start with ref == 1 to prevent IPPH_REFRELE() from
398 * attempting to free them, hence they should have 1 now.
399 */
400 ipsec_polhead_destroy(&ipss->ipsec_system_policy);
401 ASSERT(ipss->ipsec_system_policy.iph_refs == 1);
402 ipsec_polhead_destroy(&ipss->ipsec_inactive_policy);
403 ASSERT(ipss->ipsec_inactive_policy.iph_refs == 1);
404
405 for (i = 0; i < IPSEC_ACTION_HASH_SIZE; i++) {
406 ipsec_action_free_table(ipss->ipsec_action_hash[i].hash_head);
407 ipss->ipsec_action_hash[i].hash_head = NULL;
408 mutex_destroy(&(ipss->ipsec_action_hash[i].hash_lock));
409 }
410
411 for (i = 0; i < ipss->ipsec_spd_hashsize; i++) {
412 ASSERT(ipss->ipsec_sel_hash[i].hash_head == NULL);
413 mutex_destroy(&(ipss->ipsec_sel_hash[i].hash_lock));
414 }
415
416 mutex_enter(&ipss->ipsec_alg_lock);
417 for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype ++) {
418 int nalgs = ipss->ipsec_nalgs[algtype];
419
420 for (i = 0; i < nalgs; i++) {
421 if (ipss->ipsec_alglists[algtype][i] != NULL)
422 ipsec_alg_unreg(algtype, i, ns);
423 }
424 }
425 mutex_exit(&ipss->ipsec_alg_lock);
426 mutex_destroy(&ipss->ipsec_alg_lock);
427
428 ipsid_gc(ns);
429 ipsid_fini(ns);
430
431 (void) ipsec_free_tables(ipss);
432 kmem_free(ipss, sizeof (*ipss));
433 }
434
435 void
436 ipsec_policy_g_destroy(void)
437 {
438 kmem_cache_destroy(ipsec_action_cache);
439 kmem_cache_destroy(ipsec_sel_cache);
440 kmem_cache_destroy(ipsec_pol_cache);
441
442 ipsec_unregister_prov_update();
443
444 netstack_unregister(NS_IPSEC);
445 }
446
638 ipss->ipsec_spd_hashsize);
639 ipsec_polhead_init(&ipss->ipsec_inactive_policy,
640 ipss->ipsec_spd_hashsize);
641 rw_init(&ipss->ipsec_tunnel_policy_lock, NULL, RW_DEFAULT, NULL);
642 avl_create(&ipss->ipsec_tunnel_policies, tunnel_compare,
643 sizeof (ipsec_tun_pol_t), 0);
644
645 ipss->ipsec_next_policy_index = 1;
646
647 rw_init(&ipss->ipsec_system_policy.iph_lock, NULL, RW_DEFAULT, NULL);
648 rw_init(&ipss->ipsec_inactive_policy.iph_lock, NULL, RW_DEFAULT, NULL);
649
650 for (i = 0; i < IPSEC_ACTION_HASH_SIZE; i++)
651 mutex_init(&(ipss->ipsec_action_hash[i].hash_lock),
652 NULL, MUTEX_DEFAULT, NULL);
653
654 for (i = 0; i < ipss->ipsec_spd_hashsize; i++)
655 mutex_init(&(ipss->ipsec_sel_hash[i].hash_lock),
656 NULL, MUTEX_DEFAULT, NULL);
657
658 mutex_init(&ipss->ipsec_alg_lock, NULL, MUTEX_DEFAULT, NULL);
659 for (i = 0; i < IPSEC_NALGTYPES; i++) {
660 ipss->ipsec_nalgs[i] = 0;
661 }
662
663 ip_drop_init(ipss);
664 ip_drop_register(&ipss->ipsec_spd_dropper, "IPsec SPD");
665
666 /* IP's IPsec code calls the packet dropper */
667 ip_drop_register(&ipss->ipsec_dropper, "IP IPsec processing");
668
669 (void) ipsec_kstat_init(ipss);
670
671 ipsec_loader_init(ipss);
672 ipsec_loader_start(ipss);
673
674 return (ipss);
675 }
676
677 /* Global across all stack instances */
678 void
701 *
702 * I may need to split this based on
703 * authentication/encryption, and I may wish to have an administrator
704 * configure this list. Hold on to some NDD variables...
705 *
706 * XXX For now, sort on minimum key size (GAG!). While minimum key size is
707 * not the ideal metric, it's the only quantifiable measure available.
708 * We need a better metric for sorting algorithms by preference.
709 */
710 static void
711 alg_insert_sortlist(enum ipsec_algtype at, uint8_t algid, netstack_t *ns)
712 {
713 ipsec_stack_t *ipss = ns->netstack_ipsec;
714 ipsec_alginfo_t *ai = ipss->ipsec_alglists[at][algid];
715 uint8_t holder, swap;
716 uint_t i;
717 uint_t count = ipss->ipsec_nalgs[at];
718 ASSERT(ai != NULL);
719 ASSERT(algid == ai->alg_id);
720
721 ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
722
723 holder = algid;
724
725 for (i = 0; i < count - 1; i++) {
726 ipsec_alginfo_t *alt;
727
728 alt = ipss->ipsec_alglists[at][ipss->ipsec_sortlist[at][i]];
729 /*
730 * If you want to give precedence to newly added algs,
731 * add the = in the > comparison.
732 */
733 if ((holder != algid) || (ai->alg_minbits > alt->alg_minbits)) {
734 /* Swap sortlist[i] and holder. */
735 swap = ipss->ipsec_sortlist[at][i];
736 ipss->ipsec_sortlist[at][i] = holder;
737 holder = swap;
738 ai = alt;
739 } /* Else just continue. */
740 }
741
742 /* Store holder in last slot. */
743 ipss->ipsec_sortlist[at][i] = holder;
744 }
745
746 /*
747 * Remove an algorithm from a sorted algorithm list.
748 * This should be considerably easier, even with complex sorting.
749 */
750 static void
751 alg_remove_sortlist(enum ipsec_algtype at, uint8_t algid, netstack_t *ns)
752 {
753 boolean_t copyback = B_FALSE;
754 int i;
755 ipsec_stack_t *ipss = ns->netstack_ipsec;
756 int newcount = ipss->ipsec_nalgs[at];
757
758 ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
759
760 for (i = 0; i <= newcount; i++) {
761 if (copyback) {
762 ipss->ipsec_sortlist[at][i-1] =
763 ipss->ipsec_sortlist[at][i];
764 } else if (ipss->ipsec_sortlist[at][i] == algid) {
765 copyback = B_TRUE;
766 }
767 }
768 }
769
770 /*
771 * Add the specified algorithm to the algorithm tables.
772 * Must be called while holding the algorithm table writer lock.
773 */
774 void
775 ipsec_alg_reg(ipsec_algtype_t algtype, ipsec_alginfo_t *alg, netstack_t *ns)
776 {
777 ipsec_stack_t *ipss = ns->netstack_ipsec;
778
779 ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
780
781 ASSERT(ipss->ipsec_alglists[algtype][alg->alg_id] == NULL);
782 ipsec_alg_fix_min_max(alg, algtype, ns);
783 ipss->ipsec_alglists[algtype][alg->alg_id] = alg;
784
785 ipss->ipsec_nalgs[algtype]++;
786 alg_insert_sortlist(algtype, alg->alg_id, ns);
787 }
788
789 /*
790 * Remove the specified algorithm from the algorithm tables.
791 * Must be called while holding the algorithm table writer lock.
792 */
793 void
794 ipsec_alg_unreg(ipsec_algtype_t algtype, uint8_t algid, netstack_t *ns)
795 {
796 ipsec_stack_t *ipss = ns->netstack_ipsec;
797
798 ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
799
800 ASSERT(ipss->ipsec_alglists[algtype][algid] != NULL);
801 ipsec_alg_free(ipss->ipsec_alglists[algtype][algid]);
802 ipss->ipsec_alglists[algtype][algid] = NULL;
803
804 ipss->ipsec_nalgs[algtype]--;
805 alg_remove_sortlist(algtype, algid, ns);
806 }
807
808 /*
809 * Hooks for spdsock to get a grip on system policy.
810 */
811
812 ipsec_policy_head_t *
813 ipsec_system_policy(netstack_t *ns)
814 {
815 ipsec_stack_t *ipss = ns->netstack_ipsec;
816 ipsec_policy_head_t *h = &ipss->ipsec_system_policy;
817
818 IPPH_REFHOLD(h);
4670 }
4671
4672 /*
4673 * Free identity table (preparatory to module unload)
4674 */
4675 static void
4676 ipsid_fini(netstack_t *ns)
4677 {
4678 ipsif_t *bucket;
4679 int i;
4680 ipsec_stack_t *ipss = ns->netstack_ipsec;
4681
4682 for (i = 0; i < IPSID_HASHSIZE; i++) {
4683 bucket = &ipss->ipsec_ipsid_buckets[i];
4684 ASSERT(bucket->ipsif_head == NULL);
4685 mutex_destroy(&bucket->ipsif_lock);
4686 }
4687 }
4688
4689 /*
4690 * Update the minimum and maximum supported key sizes for the
4691 * specified algorithm. Must be called while holding the algorithms lock.
4692 */
4693 void
4694 ipsec_alg_fix_min_max(ipsec_alginfo_t *alg, ipsec_algtype_t alg_type,
4695 netstack_t *ns)
4696 {
4697 size_t crypto_min = (size_t)-1, crypto_max = 0;
4698 size_t cur_crypto_min, cur_crypto_max;
4699 boolean_t is_valid;
4700 crypto_mechanism_info_t *mech_infos;
4701 uint_t nmech_infos;
4702 int crypto_rc, i;
4703 crypto_mech_usage_t mask;
4704 ipsec_stack_t *ipss = ns->netstack_ipsec;
4705
4706 ASSERT(MUTEX_HELD(&ipss->ipsec_alg_lock));
4707
4708 /*
4709 * Compute the min, max, and default key sizes (in number of
4710 * increments to the default key size in bits) as defined
4711 * by the algorithm mappings. This range of key sizes is used
4712 * for policy related operations. The effective key sizes
4713 * supported by the framework could be more limited than
4714 * those defined for an algorithm.
4715 */
4716 alg->alg_default_bits = alg->alg_key_sizes[0];
4717 alg->alg_default = 0;
4718 if (alg->alg_increment != 0) {
4719 /* key sizes are defined by range & increment */
4720 alg->alg_minbits = alg->alg_key_sizes[1];
4721 alg->alg_maxbits = alg->alg_key_sizes[2];
4722 } else if (alg->alg_nkey_sizes == 0) {
4723 /* no specified key size for algorithm */
4724 alg->alg_minbits = alg->alg_maxbits = 0;
4725 } else {
4726 /* key sizes are defined by enumeration */
5039 crypto_mech_name_t *mechs;
5040 boolean_t alg_changed = B_FALSE;
5041 ipsec_stack_t *ipss = ns->netstack_ipsec;
5042
5043 /* ignore events for which we didn't register */
5044 if (event != CRYPTO_EVENT_MECHS_CHANGED) {
5045 ip1dbg(("ipsec_prov_update_callback: unexpected event 0x%x "
5046 " received from crypto framework\n", event));
5047 return;
5048 }
5049
5050 mechs = crypto_get_mech_list(&mech_count, KM_SLEEP);
5051 if (mechs == NULL)
5052 return;
5053
5054 /*
5055 * Walk the list of currently defined IPsec algorithm. Update
5056 * the algorithm valid flag and trigger an update of the
5057 * SAs that depend on that algorithm.
5058 */
5059 mutex_enter(&ipss->ipsec_alg_lock);
5060 for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype++) {
5061 for (algidx = 0; algidx < ipss->ipsec_nalgs[algtype];
5062 algidx++) {
5063
5064 algid = ipss->ipsec_sortlist[algtype][algidx];
5065 alg = ipss->ipsec_alglists[algtype][algid];
5066 ASSERT(alg != NULL);
5067
5068 /*
5069 * Skip the algorithms which do not map to the
5070 * crypto framework provider being added or removed.
5071 */
5072 if (strncmp(alg->alg_mech_name,
5073 prov_change->ec_mech_name,
5074 CRYPTO_MAX_MECH_NAME) != 0)
5075 continue;
5076
5077 /*
5078 * Determine if the mechanism is valid. If it
5079 * is not, mark the algorithm as being invalid. If
5102 ipsec_alg_fix_min_max(alg, algtype, ns);
5103 if (!alg_changed &&
5104 alg->alg_ef_minbits != oalg.alg_ef_minbits ||
5105 alg->alg_ef_maxbits != oalg.alg_ef_maxbits ||
5106 alg->alg_ef_default != oalg.alg_ef_default ||
5107 alg->alg_ef_default_bits !=
5108 oalg.alg_ef_default_bits)
5109 alg_changed = B_TRUE;
5110
5111 /*
5112 * Update the affected SAs if a software provider is
5113 * being added or removed.
5114 */
5115 if (prov_change->ec_provider_type ==
5116 CRYPTO_SW_PROVIDER)
5117 sadb_alg_update(algtype, alg->alg_id,
5118 prov_change->ec_change ==
5119 CRYPTO_MECH_ADDED, ns);
5120 }
5121 }
5122 mutex_exit(&ipss->ipsec_alg_lock);
5123 crypto_free_mech_list(mechs, mech_count);
5124
5125 if (alg_changed) {
5126 /*
5127 * An algorithm has changed, i.e. it became valid or
5128 * invalid, or its support key sizes have changed.
5129 * Notify ipsecah and ipsecesp of this change so
5130 * that they can send a SADB_REGISTER to their consumers.
5131 */
5132 ipsecah_algs_changed(ns);
5133 ipsecesp_algs_changed(ns);
5134 }
5135 }
5136
5137 /*
5138 * Registers with the crypto framework to be notified of crypto
5139 * providers changes. Used to update the algorithm tables and
5140 * to free or create context templates if needed. Invoked after IPsec
5141 * is loaded successfully.
5142 *
|
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 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2012 Nexenta Systems, Inc. All rights reserved.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
26 * Copyright (c) 2017, Joyent, Inc.
27 */
28
29 /*
30 * IPsec Security Policy Database.
31 *
32 * This module maintains the SPD and provides routines used by ip and ip6
33 * to apply IPsec policy to inbound and outbound datagrams.
34 */
35
36 #include <sys/types.h>
37 #include <sys/stream.h>
38 #include <sys/stropts.h>
39 #include <sys/sysmacros.h>
40 #include <sys/strsubr.h>
41 #include <sys/strsun.h>
42 #include <sys/strlog.h>
43 #include <sys/strsun.h>
44 #include <sys/cmn_err.h>
45 #include <sys/zone.h>
46
398 /*
399 * Globals start with ref == 1 to prevent IPPH_REFRELE() from
400 * attempting to free them, hence they should have 1 now.
401 */
402 ipsec_polhead_destroy(&ipss->ipsec_system_policy);
403 ASSERT(ipss->ipsec_system_policy.iph_refs == 1);
404 ipsec_polhead_destroy(&ipss->ipsec_inactive_policy);
405 ASSERT(ipss->ipsec_inactive_policy.iph_refs == 1);
406
407 for (i = 0; i < IPSEC_ACTION_HASH_SIZE; i++) {
408 ipsec_action_free_table(ipss->ipsec_action_hash[i].hash_head);
409 ipss->ipsec_action_hash[i].hash_head = NULL;
410 mutex_destroy(&(ipss->ipsec_action_hash[i].hash_lock));
411 }
412
413 for (i = 0; i < ipss->ipsec_spd_hashsize; i++) {
414 ASSERT(ipss->ipsec_sel_hash[i].hash_head == NULL);
415 mutex_destroy(&(ipss->ipsec_sel_hash[i].hash_lock));
416 }
417
418 rw_enter(&ipss->ipsec_alg_lock, RW_WRITER);
419 for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype ++) {
420 int nalgs = ipss->ipsec_nalgs[algtype];
421
422 for (i = 0; i < nalgs; i++) {
423 if (ipss->ipsec_alglists[algtype][i] != NULL)
424 ipsec_alg_unreg(algtype, i, ns);
425 }
426 }
427 rw_exit(&ipss->ipsec_alg_lock);
428 rw_destroy(&ipss->ipsec_alg_lock);
429
430 ipsid_gc(ns);
431 ipsid_fini(ns);
432
433 (void) ipsec_free_tables(ipss);
434 kmem_free(ipss, sizeof (*ipss));
435 }
436
437 void
438 ipsec_policy_g_destroy(void)
439 {
440 kmem_cache_destroy(ipsec_action_cache);
441 kmem_cache_destroy(ipsec_sel_cache);
442 kmem_cache_destroy(ipsec_pol_cache);
443
444 ipsec_unregister_prov_update();
445
446 netstack_unregister(NS_IPSEC);
447 }
448
640 ipss->ipsec_spd_hashsize);
641 ipsec_polhead_init(&ipss->ipsec_inactive_policy,
642 ipss->ipsec_spd_hashsize);
643 rw_init(&ipss->ipsec_tunnel_policy_lock, NULL, RW_DEFAULT, NULL);
644 avl_create(&ipss->ipsec_tunnel_policies, tunnel_compare,
645 sizeof (ipsec_tun_pol_t), 0);
646
647 ipss->ipsec_next_policy_index = 1;
648
649 rw_init(&ipss->ipsec_system_policy.iph_lock, NULL, RW_DEFAULT, NULL);
650 rw_init(&ipss->ipsec_inactive_policy.iph_lock, NULL, RW_DEFAULT, NULL);
651
652 for (i = 0; i < IPSEC_ACTION_HASH_SIZE; i++)
653 mutex_init(&(ipss->ipsec_action_hash[i].hash_lock),
654 NULL, MUTEX_DEFAULT, NULL);
655
656 for (i = 0; i < ipss->ipsec_spd_hashsize; i++)
657 mutex_init(&(ipss->ipsec_sel_hash[i].hash_lock),
658 NULL, MUTEX_DEFAULT, NULL);
659
660 rw_init(&ipss->ipsec_alg_lock, NULL, RW_DEFAULT, NULL);
661 for (i = 0; i < IPSEC_NALGTYPES; i++) {
662 ipss->ipsec_nalgs[i] = 0;
663 }
664
665 ip_drop_init(ipss);
666 ip_drop_register(&ipss->ipsec_spd_dropper, "IPsec SPD");
667
668 /* IP's IPsec code calls the packet dropper */
669 ip_drop_register(&ipss->ipsec_dropper, "IP IPsec processing");
670
671 (void) ipsec_kstat_init(ipss);
672
673 ipsec_loader_init(ipss);
674 ipsec_loader_start(ipss);
675
676 return (ipss);
677 }
678
679 /* Global across all stack instances */
680 void
703 *
704 * I may need to split this based on
705 * authentication/encryption, and I may wish to have an administrator
706 * configure this list. Hold on to some NDD variables...
707 *
708 * XXX For now, sort on minimum key size (GAG!). While minimum key size is
709 * not the ideal metric, it's the only quantifiable measure available.
710 * We need a better metric for sorting algorithms by preference.
711 */
712 static void
713 alg_insert_sortlist(enum ipsec_algtype at, uint8_t algid, netstack_t *ns)
714 {
715 ipsec_stack_t *ipss = ns->netstack_ipsec;
716 ipsec_alginfo_t *ai = ipss->ipsec_alglists[at][algid];
717 uint8_t holder, swap;
718 uint_t i;
719 uint_t count = ipss->ipsec_nalgs[at];
720 ASSERT(ai != NULL);
721 ASSERT(algid == ai->alg_id);
722
723 ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
724
725 holder = algid;
726
727 for (i = 0; i < count - 1; i++) {
728 ipsec_alginfo_t *alt;
729
730 alt = ipss->ipsec_alglists[at][ipss->ipsec_sortlist[at][i]];
731 /*
732 * If you want to give precedence to newly added algs,
733 * add the = in the > comparison.
734 */
735 if ((holder != algid) || (ai->alg_minbits > alt->alg_minbits)) {
736 /* Swap sortlist[i] and holder. */
737 swap = ipss->ipsec_sortlist[at][i];
738 ipss->ipsec_sortlist[at][i] = holder;
739 holder = swap;
740 ai = alt;
741 } /* Else just continue. */
742 }
743
744 /* Store holder in last slot. */
745 ipss->ipsec_sortlist[at][i] = holder;
746 }
747
748 /*
749 * Remove an algorithm from a sorted algorithm list.
750 * This should be considerably easier, even with complex sorting.
751 */
752 static void
753 alg_remove_sortlist(enum ipsec_algtype at, uint8_t algid, netstack_t *ns)
754 {
755 boolean_t copyback = B_FALSE;
756 int i;
757 ipsec_stack_t *ipss = ns->netstack_ipsec;
758 int newcount = ipss->ipsec_nalgs[at];
759
760 ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
761
762 for (i = 0; i <= newcount; i++) {
763 if (copyback) {
764 ipss->ipsec_sortlist[at][i-1] =
765 ipss->ipsec_sortlist[at][i];
766 } else if (ipss->ipsec_sortlist[at][i] == algid) {
767 copyback = B_TRUE;
768 }
769 }
770 }
771
772 /*
773 * Add the specified algorithm to the algorithm tables.
774 * Must be called while holding the algorithm table writer lock.
775 */
776 void
777 ipsec_alg_reg(ipsec_algtype_t algtype, ipsec_alginfo_t *alg, netstack_t *ns)
778 {
779 ipsec_stack_t *ipss = ns->netstack_ipsec;
780
781 ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
782
783 ASSERT(ipss->ipsec_alglists[algtype][alg->alg_id] == NULL);
784 ipsec_alg_fix_min_max(alg, algtype, ns);
785 ipss->ipsec_alglists[algtype][alg->alg_id] = alg;
786
787 ipss->ipsec_nalgs[algtype]++;
788 alg_insert_sortlist(algtype, alg->alg_id, ns);
789 }
790
791 /*
792 * Remove the specified algorithm from the algorithm tables.
793 * Must be called while holding the algorithm table writer lock.
794 */
795 void
796 ipsec_alg_unreg(ipsec_algtype_t algtype, uint8_t algid, netstack_t *ns)
797 {
798 ipsec_stack_t *ipss = ns->netstack_ipsec;
799
800 ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
801
802 ASSERT(ipss->ipsec_alglists[algtype][algid] != NULL);
803 ipsec_alg_free(ipss->ipsec_alglists[algtype][algid]);
804 ipss->ipsec_alglists[algtype][algid] = NULL;
805
806 ipss->ipsec_nalgs[algtype]--;
807 alg_remove_sortlist(algtype, algid, ns);
808 }
809
810 /*
811 * Hooks for spdsock to get a grip on system policy.
812 */
813
814 ipsec_policy_head_t *
815 ipsec_system_policy(netstack_t *ns)
816 {
817 ipsec_stack_t *ipss = ns->netstack_ipsec;
818 ipsec_policy_head_t *h = &ipss->ipsec_system_policy;
819
820 IPPH_REFHOLD(h);
4672 }
4673
4674 /*
4675 * Free identity table (preparatory to module unload)
4676 */
4677 static void
4678 ipsid_fini(netstack_t *ns)
4679 {
4680 ipsif_t *bucket;
4681 int i;
4682 ipsec_stack_t *ipss = ns->netstack_ipsec;
4683
4684 for (i = 0; i < IPSID_HASHSIZE; i++) {
4685 bucket = &ipss->ipsec_ipsid_buckets[i];
4686 ASSERT(bucket->ipsif_head == NULL);
4687 mutex_destroy(&bucket->ipsif_lock);
4688 }
4689 }
4690
4691 /*
4692 * Update the minimum and maximum supported key sizes for the specified
4693 * algorithm, which is either a member of a netstack alg array or about to be,
4694 * and therefore must be called holding ipsec_alg_lock for write.
4695 */
4696 void
4697 ipsec_alg_fix_min_max(ipsec_alginfo_t *alg, ipsec_algtype_t alg_type,
4698 netstack_t *ns)
4699 {
4700 size_t crypto_min = (size_t)-1, crypto_max = 0;
4701 size_t cur_crypto_min, cur_crypto_max;
4702 boolean_t is_valid;
4703 crypto_mechanism_info_t *mech_infos;
4704 uint_t nmech_infos;
4705 int crypto_rc, i;
4706 crypto_mech_usage_t mask;
4707 ipsec_stack_t *ipss = ns->netstack_ipsec;
4708
4709 ASSERT(RW_WRITE_HELD(&ipss->ipsec_alg_lock));
4710
4711 /*
4712 * Compute the min, max, and default key sizes (in number of
4713 * increments to the default key size in bits) as defined
4714 * by the algorithm mappings. This range of key sizes is used
4715 * for policy related operations. The effective key sizes
4716 * supported by the framework could be more limited than
4717 * those defined for an algorithm.
4718 */
4719 alg->alg_default_bits = alg->alg_key_sizes[0];
4720 alg->alg_default = 0;
4721 if (alg->alg_increment != 0) {
4722 /* key sizes are defined by range & increment */
4723 alg->alg_minbits = alg->alg_key_sizes[1];
4724 alg->alg_maxbits = alg->alg_key_sizes[2];
4725 } else if (alg->alg_nkey_sizes == 0) {
4726 /* no specified key size for algorithm */
4727 alg->alg_minbits = alg->alg_maxbits = 0;
4728 } else {
4729 /* key sizes are defined by enumeration */
5042 crypto_mech_name_t *mechs;
5043 boolean_t alg_changed = B_FALSE;
5044 ipsec_stack_t *ipss = ns->netstack_ipsec;
5045
5046 /* ignore events for which we didn't register */
5047 if (event != CRYPTO_EVENT_MECHS_CHANGED) {
5048 ip1dbg(("ipsec_prov_update_callback: unexpected event 0x%x "
5049 " received from crypto framework\n", event));
5050 return;
5051 }
5052
5053 mechs = crypto_get_mech_list(&mech_count, KM_SLEEP);
5054 if (mechs == NULL)
5055 return;
5056
5057 /*
5058 * Walk the list of currently defined IPsec algorithm. Update
5059 * the algorithm valid flag and trigger an update of the
5060 * SAs that depend on that algorithm.
5061 */
5062 rw_enter(&ipss->ipsec_alg_lock, RW_WRITER);
5063 for (algtype = 0; algtype < IPSEC_NALGTYPES; algtype++) {
5064 for (algidx = 0; algidx < ipss->ipsec_nalgs[algtype];
5065 algidx++) {
5066
5067 algid = ipss->ipsec_sortlist[algtype][algidx];
5068 alg = ipss->ipsec_alglists[algtype][algid];
5069 ASSERT(alg != NULL);
5070
5071 /*
5072 * Skip the algorithms which do not map to the
5073 * crypto framework provider being added or removed.
5074 */
5075 if (strncmp(alg->alg_mech_name,
5076 prov_change->ec_mech_name,
5077 CRYPTO_MAX_MECH_NAME) != 0)
5078 continue;
5079
5080 /*
5081 * Determine if the mechanism is valid. If it
5082 * is not, mark the algorithm as being invalid. If
5105 ipsec_alg_fix_min_max(alg, algtype, ns);
5106 if (!alg_changed &&
5107 alg->alg_ef_minbits != oalg.alg_ef_minbits ||
5108 alg->alg_ef_maxbits != oalg.alg_ef_maxbits ||
5109 alg->alg_ef_default != oalg.alg_ef_default ||
5110 alg->alg_ef_default_bits !=
5111 oalg.alg_ef_default_bits)
5112 alg_changed = B_TRUE;
5113
5114 /*
5115 * Update the affected SAs if a software provider is
5116 * being added or removed.
5117 */
5118 if (prov_change->ec_provider_type ==
5119 CRYPTO_SW_PROVIDER)
5120 sadb_alg_update(algtype, alg->alg_id,
5121 prov_change->ec_change ==
5122 CRYPTO_MECH_ADDED, ns);
5123 }
5124 }
5125 rw_exit(&ipss->ipsec_alg_lock);
5126 crypto_free_mech_list(mechs, mech_count);
5127
5128 if (alg_changed) {
5129 /*
5130 * An algorithm has changed, i.e. it became valid or
5131 * invalid, or its support key sizes have changed.
5132 * Notify ipsecah and ipsecesp of this change so
5133 * that they can send a SADB_REGISTER to their consumers.
5134 */
5135 ipsecah_algs_changed(ns);
5136 ipsecesp_algs_changed(ns);
5137 }
5138 }
5139
5140 /*
5141 * Registers with the crypto framework to be notified of crypto
5142 * providers changes. Used to update the algorithm tables and
5143 * to free or create context templates if needed. Invoked after IPsec
5144 * is loaded successfully.
5145 *
|