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