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