aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2007-09-16 22:34:00 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:51:32 -0400
commit65b07e5d0d09c77e98050b5f0146ead29e5add32 (patch)
treeb5c5ac79969401238ce2c01d3999016238b02b93 /net
parentbbd0d59809f923ea2b540cbd781b32110e249f6e (diff)
[SCTP]: API updates to suport SCTP-AUTH extensions.
Add SCTP-AUTH API. The API implemented here was agreed to between implementors at the 9th SCTP Interop. It will be documented in the next revision of the SCTP socket API spec. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/sctp/auth.c193
-rw-r--r--net/sctp/sm_statefuns.c13
-rw-r--r--net/sctp/socket.c304
-rw-r--r--net/sctp/ulpevent.c37
4 files changed, 547 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 */
750int 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 */
772int 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 */
806int 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;
860nomem:
861 if (!replace)
862 sctp_auth_shkey_free(cur_key);
863
864 return -ENOMEM;
865}
866
867int 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
900int 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}
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 5aef4aafdfdc..f01b408508ff 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -3848,6 +3848,19 @@ sctp_disposition_t sctp_sf_eat_auth(const struct sctp_endpoint *ep,
3848 break; 3848 break;
3849 } 3849 }
3850 3850
3851 if (asoc->active_key_id != ntohs(auth_hdr->shkey_id)) {
3852 struct sctp_ulpevent *ev;
3853
3854 ev = sctp_ulpevent_make_authkey(asoc, ntohs(auth_hdr->shkey_id),
3855 SCTP_AUTH_NEWKEY, GFP_ATOMIC);
3856
3857 if (!ev)
3858 return -ENOMEM;
3859
3860 sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
3861 SCTP_ULPEVENT(ev));
3862 }
3863
3851 return SCTP_DISPOSITION_CONSUME; 3864 return SCTP_DISPOSITION_CONSUME;
3852} 3865}
3853 3866
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 7738915011a0..f3e1a9c811ad 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -2946,6 +2946,164 @@ static int sctp_setsockopt_maxburst(struct sock *sk,
2946 return 0; 2946 return 0;
2947} 2947}
2948 2948
2949/*
2950 * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK)
2951 *
2952 * This set option adds a chunk type that the user is requesting to be
2953 * received only in an authenticated way. Changes to the list of chunks
2954 * will only effect future associations on the socket.
2955 */
2956static int sctp_setsockopt_auth_chunk(struct sock *sk,
2957 char __user *optval,
2958 int optlen)
2959{
2960 struct sctp_authchunk val;
2961
2962 if (optlen != sizeof(struct sctp_authchunk))
2963 return -EINVAL;
2964 if (copy_from_user(&val, optval, optlen))
2965 return -EFAULT;
2966
2967 switch (val.sauth_chunk) {
2968 case SCTP_CID_INIT:
2969 case SCTP_CID_INIT_ACK:
2970 case SCTP_CID_SHUTDOWN_COMPLETE:
2971 case SCTP_CID_AUTH:
2972 return -EINVAL;
2973 }
2974
2975 /* add this chunk id to the endpoint */
2976 return sctp_auth_ep_add_chunkid(sctp_sk(sk)->ep, val.sauth_chunk);
2977}
2978
2979/*
2980 * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT)
2981 *
2982 * This option gets or sets the list of HMAC algorithms that the local
2983 * endpoint requires the peer to use.
2984 */
2985static int sctp_setsockopt_hmac_ident(struct sock *sk,
2986 char __user *optval,
2987 int optlen)
2988{
2989 struct sctp_hmacalgo *hmacs;
2990 int err;
2991
2992 if (optlen < sizeof(struct sctp_hmacalgo))
2993 return -EINVAL;
2994
2995 hmacs = kmalloc(optlen, GFP_KERNEL);
2996 if (!hmacs)
2997 return -ENOMEM;
2998
2999 if (copy_from_user(hmacs, optval, optlen)) {
3000 err = -EFAULT;
3001 goto out;
3002 }
3003
3004 if (hmacs->shmac_num_idents == 0 ||
3005 hmacs->shmac_num_idents > SCTP_AUTH_NUM_HMACS) {
3006 err = -EINVAL;
3007 goto out;
3008 }
3009
3010 err = sctp_auth_ep_set_hmacs(sctp_sk(sk)->ep, hmacs);
3011out:
3012 kfree(hmacs);
3013 return err;
3014}
3015
3016/*
3017 * 7.1.20. Set a shared key (SCTP_AUTH_KEY)
3018 *
3019 * This option will set a shared secret key which is used to build an
3020 * association shared key.
3021 */
3022static int sctp_setsockopt_auth_key(struct sock *sk,
3023 char __user *optval,
3024 int optlen)
3025{
3026 struct sctp_authkey *authkey;
3027 struct sctp_association *asoc;
3028 int ret;
3029
3030 if (optlen <= sizeof(struct sctp_authkey))
3031 return -EINVAL;
3032
3033 authkey = kmalloc(optlen, GFP_KERNEL);
3034 if (!authkey)
3035 return -ENOMEM;
3036
3037 if (copy_from_user(authkey, optval, optlen)) {
3038 ret = -EFAULT;
3039 goto out;
3040 }
3041
3042 asoc = sctp_id2assoc(sk, authkey->sca_assoc_id);
3043 if (!asoc && authkey->sca_assoc_id && sctp_style(sk, UDP)) {
3044 ret = -EINVAL;
3045 goto out;
3046 }
3047
3048 ret = sctp_auth_set_key(sctp_sk(sk)->ep, asoc, authkey);
3049out:
3050 kfree(authkey);
3051 return ret;
3052}
3053
3054/*
3055 * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY)
3056 *
3057 * This option will get or set the active shared key to be used to build
3058 * the association shared key.
3059 */
3060static int sctp_setsockopt_active_key(struct sock *sk,
3061 char __user *optval,
3062 int optlen)
3063{
3064 struct sctp_authkeyid val;
3065 struct sctp_association *asoc;
3066
3067 if (optlen != sizeof(struct sctp_authkeyid))
3068 return -EINVAL;
3069 if (copy_from_user(&val, optval, optlen))
3070 return -EFAULT;
3071
3072 asoc = sctp_id2assoc(sk, val.scact_assoc_id);
3073 if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))
3074 return -EINVAL;
3075
3076 return sctp_auth_set_active_key(sctp_sk(sk)->ep, asoc,
3077 val.scact_keynumber);
3078}
3079
3080/*
3081 * 7.1.22. Delete a shared key (SCTP_AUTH_DELETE_KEY)
3082 *
3083 * This set option will delete a shared secret key from use.
3084 */
3085static int sctp_setsockopt_del_key(struct sock *sk,
3086 char __user *optval,
3087 int optlen)
3088{
3089 struct sctp_authkeyid val;
3090 struct sctp_association *asoc;
3091
3092 if (optlen != sizeof(struct sctp_authkeyid))
3093 return -EINVAL;
3094 if (copy_from_user(&val, optval, optlen))
3095 return -EFAULT;
3096
3097 asoc = sctp_id2assoc(sk, val.scact_assoc_id);
3098 if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))
3099 return -EINVAL;
3100
3101 return sctp_auth_del_key_id(sctp_sk(sk)->ep, asoc,
3102 val.scact_keynumber);
3103
3104}
3105
3106
2949/* API 6.2 setsockopt(), getsockopt() 3107/* API 6.2 setsockopt(), getsockopt()
2950 * 3108 *
2951 * Applications use setsockopt() and getsockopt() to set or retrieve 3109 * Applications use setsockopt() and getsockopt() to set or retrieve
@@ -3069,6 +3227,21 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
3069 case SCTP_MAX_BURST: 3227 case SCTP_MAX_BURST:
3070 retval = sctp_setsockopt_maxburst(sk, optval, optlen); 3228 retval = sctp_setsockopt_maxburst(sk, optval, optlen);
3071 break; 3229 break;
3230 case SCTP_AUTH_CHUNK:
3231 retval = sctp_setsockopt_auth_chunk(sk, optval, optlen);
3232 break;
3233 case SCTP_HMAC_IDENT:
3234 retval = sctp_setsockopt_hmac_ident(sk, optval, optlen);
3235 break;
3236 case SCTP_AUTH_KEY:
3237 retval = sctp_setsockopt_auth_key(sk, optval, optlen);
3238 break;
3239 case SCTP_AUTH_ACTIVE_KEY:
3240 retval = sctp_setsockopt_active_key(sk, optval, optlen);
3241 break;
3242 case SCTP_AUTH_DELETE_KEY:
3243 retval = sctp_setsockopt_del_key(sk, optval, optlen);
3244 break;
3072 default: 3245 default:
3073 retval = -ENOPROTOOPT; 3246 retval = -ENOPROTOOPT;
3074 break; 3247 break;
@@ -4840,6 +5013,118 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,
4840 return -ENOTSUPP; 5013 return -ENOTSUPP;
4841} 5014}
4842 5015
5016static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,
5017 char __user *optval, int __user *optlen)
5018{
5019 struct sctp_hmac_algo_param *hmacs;
5020 __u16 param_len;
5021
5022 hmacs = sctp_sk(sk)->ep->auth_hmacs_list;
5023 param_len = ntohs(hmacs->param_hdr.length);
5024
5025 if (len < param_len)
5026 return -EINVAL;
5027 if (put_user(len, optlen))
5028 return -EFAULT;
5029 if (copy_to_user(optval, hmacs->hmac_ids, len))
5030 return -EFAULT;
5031
5032 return 0;
5033}
5034
5035static int sctp_getsockopt_active_key(struct sock *sk, int len,
5036 char __user *optval, int __user *optlen)
5037{
5038 struct sctp_authkeyid val;
5039 struct sctp_association *asoc;
5040
5041 if (len < sizeof(struct sctp_authkeyid))
5042 return -EINVAL;
5043 if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid)))
5044 return -EFAULT;
5045
5046 asoc = sctp_id2assoc(sk, val.scact_assoc_id);
5047 if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))
5048 return -EINVAL;
5049
5050 if (asoc)
5051 val.scact_keynumber = asoc->active_key_id;
5052 else
5053 val.scact_keynumber = sctp_sk(sk)->ep->active_key_id;
5054
5055 return 0;
5056}
5057
5058static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
5059 char __user *optval, int __user *optlen)
5060{
5061 struct sctp_authchunks val;
5062 struct sctp_association *asoc;
5063 struct sctp_chunks_param *ch;
5064 char __user *to;
5065
5066 if (len <= sizeof(struct sctp_authchunks))
5067 return -EINVAL;
5068
5069 if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
5070 return -EFAULT;
5071
5072 to = val.gauth_chunks;
5073 asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
5074 if (!asoc)
5075 return -EINVAL;
5076
5077 ch = asoc->peer.peer_chunks;
5078
5079 /* See if the user provided enough room for all the data */
5080 if (len < ntohs(ch->param_hdr.length))
5081 return -EINVAL;
5082
5083 len = ntohs(ch->param_hdr.length);
5084 if (put_user(len, optlen))
5085 return -EFAULT;
5086 if (copy_to_user(to, ch->chunks, len))
5087 return -EFAULT;
5088
5089 return 0;
5090}
5091
5092static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
5093 char __user *optval, int __user *optlen)
5094{
5095 struct sctp_authchunks val;
5096 struct sctp_association *asoc;
5097 struct sctp_chunks_param *ch;
5098 char __user *to;
5099
5100 if (len <= sizeof(struct sctp_authchunks))
5101 return -EINVAL;
5102
5103 if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
5104 return -EFAULT;
5105
5106 to = val.gauth_chunks;
5107 asoc = sctp_id2assoc(sk, val.gauth_assoc_id);
5108 if (!asoc && val.gauth_assoc_id && sctp_style(sk, UDP))
5109 return -EINVAL;
5110
5111 if (asoc)
5112 ch = (struct sctp_chunks_param*)asoc->c.auth_chunks;
5113 else
5114 ch = sctp_sk(sk)->ep->auth_chunk_list;
5115
5116 if (len < ntohs(ch->param_hdr.length))
5117 return -EINVAL;
5118
5119 len = ntohs(ch->param_hdr.length);
5120 if (put_user(len, optlen))
5121 return -EFAULT;
5122 if (copy_to_user(to, ch->chunks, len))
5123 return -EFAULT;
5124
5125 return 0;
5126}
5127
4843SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, 5128SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
4844 char __user *optval, int __user *optlen) 5129 char __user *optval, int __user *optlen)
4845{ 5130{
@@ -4963,6 +5248,25 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
4963 case SCTP_MAX_BURST: 5248 case SCTP_MAX_BURST:
4964 retval = sctp_getsockopt_maxburst(sk, len, optval, optlen); 5249 retval = sctp_getsockopt_maxburst(sk, len, optval, optlen);
4965 break; 5250 break;
5251 case SCTP_AUTH_KEY:
5252 case SCTP_AUTH_CHUNK:
5253 case SCTP_AUTH_DELETE_KEY:
5254 retval = -EOPNOTSUPP;
5255 break;
5256 case SCTP_HMAC_IDENT:
5257 retval = sctp_getsockopt_hmac_ident(sk, len, optval, optlen);
5258 break;
5259 case SCTP_AUTH_ACTIVE_KEY:
5260 retval = sctp_getsockopt_active_key(sk, len, optval, optlen);
5261 break;
5262 case SCTP_PEER_AUTH_CHUNKS:
5263 retval = sctp_getsockopt_peer_auth_chunks(sk, len, optval,
5264 optlen);
5265 break;
5266 case SCTP_LOCAL_AUTH_CHUNKS:
5267 retval = sctp_getsockopt_local_auth_chunks(sk, len, optval,
5268 optlen);
5269 break;
4966 default: 5270 default:
4967 retval = -ENOPROTOOPT; 5271 retval = -ENOPROTOOPT;
4968 break; 5272 break;
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 5dc094b9732d..2c17c7efad46 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -813,6 +813,43 @@ fail:
813 return NULL; 813 return NULL;
814} 814}
815 815
816struct sctp_ulpevent *sctp_ulpevent_make_authkey(
817 const struct sctp_association *asoc, __u16 key_id,
818 __u32 indication, gfp_t gfp)
819{
820 struct sctp_ulpevent *event;
821 struct sctp_authkey_event *ak;
822 struct sk_buff *skb;
823
824 event = sctp_ulpevent_new(sizeof(struct sctp_authkey_event),
825 MSG_NOTIFICATION, gfp);
826 if (!event)
827 goto fail;
828
829 skb = sctp_event2skb(event);
830 ak = (struct sctp_authkey_event *)
831 skb_put(skb, sizeof(struct sctp_authkey_event));
832
833 ak->auth_type = SCTP_AUTHENTICATION_EVENT;
834 ak->auth_flags = 0;
835 ak->auth_length = sizeof(struct sctp_authkey_event);
836
837 ak->auth_keynumber = key_id;
838 ak->auth_altkeynumber = 0;
839 ak->auth_indication = indication;
840
841 /*
842 * The association id field, holds the identifier for the association.
843 */
844 sctp_ulpevent_set_owner(event, asoc);
845 ak->auth_assoc_id = sctp_assoc2id(asoc);
846
847 return event;
848fail:
849 return NULL;
850}
851
852
816/* Return the notification type, assuming this is a notification 853/* Return the notification type, assuming this is a notification
817 * event. 854 * event.
818 */ 855 */