diff options
Diffstat (limited to 'net/sctp/auth.c')
-rw-r--r-- | net/sctp/auth.c | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/net/sctp/auth.c b/net/sctp/auth.c index 2a29409a38d9..781810724714 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c | |||
@@ -743,3 +743,196 @@ free: | |||
743 | if (free_key) | 743 | if (free_key) |
744 | sctp_auth_key_put(asoc_key); | 744 | sctp_auth_key_put(asoc_key); |
745 | } | 745 | } |
746 | |||
747 | /* API Helpers */ | ||
748 | |||
749 | /* Add a chunk to the endpoint authenticated chunk list */ | ||
750 | int sctp_auth_ep_add_chunkid(struct sctp_endpoint *ep, __u8 chunk_id) | ||
751 | { | ||
752 | struct sctp_chunks_param *p = ep->auth_chunk_list; | ||
753 | __u16 nchunks; | ||
754 | __u16 param_len; | ||
755 | |||
756 | /* If this chunk is already specified, we are done */ | ||
757 | if (__sctp_auth_cid(chunk_id, p)) | ||
758 | return 0; | ||
759 | |||
760 | /* Check if we can add this chunk to the array */ | ||
761 | param_len = ntohs(p->param_hdr.length); | ||
762 | nchunks = param_len - sizeof(sctp_paramhdr_t); | ||
763 | if (nchunks == SCTP_NUM_CHUNK_TYPES) | ||
764 | return -EINVAL; | ||
765 | |||
766 | p->chunks[nchunks] = chunk_id; | ||
767 | p->param_hdr.length = htons(param_len + 1); | ||
768 | return 0; | ||
769 | } | ||
770 | |||
771 | /* Add hmac identifires to the endpoint list of supported hmac ids */ | ||
772 | int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep, | ||
773 | struct sctp_hmacalgo *hmacs) | ||
774 | { | ||
775 | int has_sha1 = 0; | ||
776 | __u16 id; | ||
777 | int i; | ||
778 | |||
779 | /* Scan the list looking for unsupported id. Also make sure that | ||
780 | * SHA1 is specified. | ||
781 | */ | ||
782 | for (i = 0; i < hmacs->shmac_num_idents; i++) { | ||
783 | id = hmacs->shmac_idents[i]; | ||
784 | |||
785 | if (SCTP_AUTH_HMAC_ID_SHA1 == id) | ||
786 | has_sha1 = 1; | ||
787 | |||
788 | if (!sctp_hmac_list[id].hmac_name) | ||
789 | return -EOPNOTSUPP; | ||
790 | } | ||
791 | |||
792 | if (!has_sha1) | ||
793 | return -EINVAL; | ||
794 | |||
795 | memcpy(ep->auth_hmacs_list->hmac_ids, &hmacs->shmac_idents[0], | ||
796 | hmacs->shmac_num_idents * sizeof(__u16)); | ||
797 | ep->auth_hmacs_list->param_hdr.length = htons(sizeof(sctp_paramhdr_t) + | ||
798 | hmacs->shmac_num_idents * sizeof(__u16)); | ||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | /* Set a new shared key on either endpoint or association. If the | ||
803 | * the key with a same ID already exists, replace the key (remove the | ||
804 | * old key and add a new one). | ||
805 | */ | ||
806 | int sctp_auth_set_key(struct sctp_endpoint *ep, | ||
807 | struct sctp_association *asoc, | ||
808 | struct sctp_authkey *auth_key) | ||
809 | { | ||
810 | struct sctp_shared_key *cur_key = NULL; | ||
811 | struct sctp_auth_bytes *key; | ||
812 | struct list_head *sh_keys; | ||
813 | int replace = 0; | ||
814 | |||
815 | /* Try to find the given key id to see if | ||
816 | * we are doing a replace, or adding a new key | ||
817 | */ | ||
818 | if (asoc) | ||
819 | sh_keys = &asoc->endpoint_shared_keys; | ||
820 | else | ||
821 | sh_keys = &ep->endpoint_shared_keys; | ||
822 | |||
823 | key_for_each(cur_key, sh_keys) { | ||
824 | if (cur_key->key_id == auth_key->sca_keynumber) { | ||
825 | replace = 1; | ||
826 | break; | ||
827 | } | ||
828 | } | ||
829 | |||
830 | /* If we are not replacing a key id, we need to allocate | ||
831 | * a shared key. | ||
832 | */ | ||
833 | if (!replace) { | ||
834 | cur_key = sctp_auth_shkey_create(auth_key->sca_keynumber, | ||
835 | GFP_KERNEL); | ||
836 | if (!cur_key) | ||
837 | return -ENOMEM; | ||
838 | } | ||
839 | |||
840 | /* Create a new key data based on the info passed in */ | ||
841 | key = sctp_auth_create_key(auth_key->sca_keylen, GFP_KERNEL); | ||
842 | if (!key) | ||
843 | goto nomem; | ||
844 | |||
845 | memcpy(key->data, &auth_key->sca_key[0], auth_key->sca_keylen); | ||
846 | |||
847 | /* If we are replacing, remove the old keys data from the | ||
848 | * key id. If we are adding new key id, add it to the | ||
849 | * list. | ||
850 | */ | ||
851 | if (replace) | ||
852 | sctp_auth_key_put(cur_key->key); | ||
853 | else | ||
854 | list_add(&cur_key->key_list, sh_keys); | ||
855 | |||
856 | cur_key->key = key; | ||
857 | sctp_auth_key_hold(key); | ||
858 | |||
859 | return 0; | ||
860 | nomem: | ||
861 | if (!replace) | ||
862 | sctp_auth_shkey_free(cur_key); | ||
863 | |||
864 | return -ENOMEM; | ||
865 | } | ||
866 | |||
867 | int sctp_auth_set_active_key(struct sctp_endpoint *ep, | ||
868 | struct sctp_association *asoc, | ||
869 | __u16 key_id) | ||
870 | { | ||
871 | struct sctp_shared_key *key; | ||
872 | struct list_head *sh_keys; | ||
873 | int found = 0; | ||
874 | |||
875 | /* The key identifier MUST correst to an existing key */ | ||
876 | if (asoc) | ||
877 | sh_keys = &asoc->endpoint_shared_keys; | ||
878 | else | ||
879 | sh_keys = &ep->endpoint_shared_keys; | ||
880 | |||
881 | key_for_each(key, sh_keys) { | ||
882 | if (key->key_id == key_id) { | ||
883 | found = 1; | ||
884 | break; | ||
885 | } | ||
886 | } | ||
887 | |||
888 | if (!found) | ||
889 | return -EINVAL; | ||
890 | |||
891 | if (asoc) { | ||
892 | asoc->active_key_id = key_id; | ||
893 | sctp_auth_asoc_init_active_key(asoc, GFP_KERNEL); | ||
894 | } else | ||
895 | ep->active_key_id = key_id; | ||
896 | |||
897 | return 0; | ||
898 | } | ||
899 | |||
900 | int sctp_auth_del_key_id(struct sctp_endpoint *ep, | ||
901 | struct sctp_association *asoc, | ||
902 | __u16 key_id) | ||
903 | { | ||
904 | struct sctp_shared_key *key; | ||
905 | struct list_head *sh_keys; | ||
906 | int found = 0; | ||
907 | |||
908 | /* The key identifier MUST NOT be the current active key | ||
909 | * The key identifier MUST correst to an existing key | ||
910 | */ | ||
911 | if (asoc) { | ||
912 | if (asoc->active_key_id == key_id) | ||
913 | return -EINVAL; | ||
914 | |||
915 | sh_keys = &asoc->endpoint_shared_keys; | ||
916 | } else { | ||
917 | if (ep->active_key_id == key_id) | ||
918 | return -EINVAL; | ||
919 | |||
920 | sh_keys = &ep->endpoint_shared_keys; | ||
921 | } | ||
922 | |||
923 | key_for_each(key, sh_keys) { | ||
924 | if (key->key_id == key_id) { | ||
925 | found = 1; | ||
926 | break; | ||
927 | } | ||
928 | } | ||
929 | |||
930 | if (!found) | ||
931 | return -EINVAL; | ||
932 | |||
933 | /* Delete the shared key */ | ||
934 | list_del_init(&key->key_list); | ||
935 | sctp_auth_shkey_free(key); | ||
936 | |||
937 | return 0; | ||
938 | } | ||