Skip to content

Commit

Permalink
Merge branch 'sctp-add-support-for-some-sctp-auth-APIs-from-RFC6458'
Browse files Browse the repository at this point in the history
Xin Long says:

====================
sctp: add support for some sctp auth APIs from RFC6458

This patchset mainly adds support for SCTP AUTH Information for sendmsg,
described in RFC6458:

    5.3.8.  SCTP AUTH Information Structure (SCTP_AUTHINFO)

and also adds a sockopt described in RFC6458:

    8.3.4.  Deactivate a Shared Key (SCTP_AUTH_DEACTIVATE_KEY)

and two types of events for AUTHENTICATION_EVENT described in RFC6458:

    6.1.8.  SCTP_AUTHENTICATION_EVENT:
             - SCTP_AUTH_NO_AUTH
             - SCTP_AUTH_FREE_KEY

After this patchset, we have fully support for sctp_sendv in kernel.

Note that this patchset won't touch that sctp options merge conflict.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Mar 14, 2018
2 parents c469012 + 30f6ebf commit c292566
Show file tree
Hide file tree
Showing 12 changed files with 342 additions and 72 deletions.
21 changes: 12 additions & 9 deletions include/net/sctp/auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ struct sctp_auth_bytes {
/* Definition for a shared key, weather endpoint or association */
struct sctp_shared_key {
struct list_head key_list;
__u16 key_id;
struct sctp_auth_bytes *key;
refcount_t refcnt;
__u16 key_id;
__u8 deactivated;
};

#define key_for_each(__key, __list_head) \
Expand Down Expand Up @@ -103,21 +105,22 @@ int sctp_auth_send_cid(enum sctp_cid chunk,
int sctp_auth_recv_cid(enum sctp_cid chunk,
const struct sctp_association *asoc);
void sctp_auth_calculate_hmac(const struct sctp_association *asoc,
struct sk_buff *skb,
struct sctp_auth_chunk *auth, gfp_t gfp);
struct sk_buff *skb, struct sctp_auth_chunk *auth,
struct sctp_shared_key *ep_key, gfp_t gfp);
void sctp_auth_shkey_release(struct sctp_shared_key *sh_key);
void sctp_auth_shkey_hold(struct sctp_shared_key *sh_key);

/* API Helpers */
int sctp_auth_ep_add_chunkid(struct sctp_endpoint *ep, __u8 chunk_id);
int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep,
struct sctp_hmacalgo *hmacs);
int sctp_auth_set_key(struct sctp_endpoint *ep,
struct sctp_association *asoc,
int sctp_auth_set_key(struct sctp_endpoint *ep, struct sctp_association *asoc,
struct sctp_authkey *auth_key);
int sctp_auth_set_active_key(struct sctp_endpoint *ep,
struct sctp_association *asoc,
__u16 key_id);
struct sctp_association *asoc, __u16 key_id);
int sctp_auth_del_key_id(struct sctp_endpoint *ep,
struct sctp_association *asoc,
__u16 key_id);
struct sctp_association *asoc, __u16 key_id);
int sctp_auth_deact_key_id(struct sctp_endpoint *ep,
struct sctp_association *asoc, __u16 key_id);

#endif
1 change: 1 addition & 0 deletions include/net/sctp/command.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ enum sctp_verb {
SCTP_CMD_SET_SK_ERR, /* Set sk_err */
SCTP_CMD_ASSOC_CHANGE, /* generate and send assoc_change event */
SCTP_CMD_ADAPTATION_IND, /* generate and send adaptation event */
SCTP_CMD_PEER_NO_AUTH, /* generate and send authentication event */
SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */
SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */
SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */
Expand Down
3 changes: 2 additions & 1 deletion include/net/sctp/sm.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,8 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
__u32 new_cum_tsn, size_t nstreams,
struct sctp_fwdtsn_skip *skiplist);
struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc);
struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc,
__u16 key_id);
struct sctp_chunk *sctp_make_strreset_req(const struct sctp_association *asoc,
__u16 stream_num, __be16 *stream_list,
bool out, bool in);
Expand Down
10 changes: 8 additions & 2 deletions include/net/sctp/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -577,8 +577,12 @@ struct sctp_chunk {
/* This points to the sk_buff containing the actual data. */
struct sk_buff *skb;

/* In case of GSO packets, this will store the head one */
struct sk_buff *head_skb;
union {
/* In case of GSO packets, this will store the head one */
struct sk_buff *head_skb;
/* In case of auth enabled, this will point to the shkey */
struct sctp_shared_key *shkey;
};

/* These are the SCTP headers by reverse order in a packet.
* Note that some of these may happen more than once. In that
Expand Down Expand Up @@ -1995,6 +1999,7 @@ struct sctp_association {
* The current generated assocaition shared key (secret)
*/
struct sctp_auth_bytes *asoc_shared_key;
struct sctp_shared_key *shkey;

/* SCTP AUTH: hmac id of the first peer requested algorithm
* that we support.
Expand Down Expand Up @@ -2113,6 +2118,7 @@ struct sctp_cmsgs {
struct sctp_sndrcvinfo *srinfo;
struct sctp_sndinfo *sinfo;
struct sctp_prinfo *prinfo;
struct sctp_authinfo *authinfo;
struct msghdr *addrs_msg;
};

Expand Down
22 changes: 20 additions & 2 deletions include/uapi/linux/sctp.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ typedef __s32 sctp_assoc_t;
#define SCTP_RECVRCVINFO 32
#define SCTP_RECVNXTINFO 33
#define SCTP_DEFAULT_SNDINFO 34
#define SCTP_AUTH_DEACTIVATE_KEY 35

/* Internal Socket Options. Some of the sctp library functions are
* implemented using these socket options.
Expand Down Expand Up @@ -273,6 +274,18 @@ struct sctp_prinfo {
__u32 pr_value;
};

/* 5.3.8 SCTP AUTH Information Structure (SCTP_AUTHINFO)
*
* This cmsghdr structure specifies SCTP options for sendmsg().
*
* cmsg_level cmsg_type cmsg_data[]
* ------------ ------------ -------------------
* IPPROTO_SCTP SCTP_AUTHINFO struct sctp_authinfo
*/
struct sctp_authinfo {
__u16 auth_keynumber;
};

/*
* sinfo_flags: 16 bits (unsigned integer)
*
Expand Down Expand Up @@ -310,7 +323,7 @@ typedef enum sctp_cmsg_type {
#define SCTP_NXTINFO SCTP_NXTINFO
SCTP_PRINFO, /* 5.3.7 SCTP PR-SCTP Information Structure */
#define SCTP_PRINFO SCTP_PRINFO
SCTP_AUTHINFO, /* 5.3.8 SCTP AUTH Information Structure (RESERVED) */
SCTP_AUTHINFO, /* 5.3.8 SCTP AUTH Information Structure */
#define SCTP_AUTHINFO SCTP_AUTHINFO
SCTP_DSTADDRV4, /* 5.3.9 SCTP Destination IPv4 Address Structure */
#define SCTP_DSTADDRV4 SCTP_DSTADDRV4
Expand Down Expand Up @@ -505,7 +518,12 @@ struct sctp_authkey_event {
sctp_assoc_t auth_assoc_id;
};

enum { SCTP_AUTH_NEWKEY = 0, };
enum {
SCTP_AUTH_NEW_KEY,
#define SCTP_AUTH_NEWKEY SCTP_AUTH_NEW_KEY /* compatible with before */
SCTP_AUTH_FREE_KEY,
SCTP_AUTH_NO_AUTH,
};

/*
* 6.1.9. SCTP_SENDER_DRY_EVENT
Expand Down
146 changes: 100 additions & 46 deletions net/sctp/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,20 +101,32 @@ struct sctp_shared_key *sctp_auth_shkey_create(__u16 key_id, gfp_t gfp)
return NULL;

INIT_LIST_HEAD(&new->key_list);
refcount_set(&new->refcnt, 1);
new->key_id = key_id;

return new;
}

/* Free the shared key structure */
static void sctp_auth_shkey_free(struct sctp_shared_key *sh_key)
static void sctp_auth_shkey_destroy(struct sctp_shared_key *sh_key)
{
BUG_ON(!list_empty(&sh_key->key_list));
sctp_auth_key_put(sh_key->key);
sh_key->key = NULL;
kfree(sh_key);
}

void sctp_auth_shkey_release(struct sctp_shared_key *sh_key)
{
if (refcount_dec_and_test(&sh_key->refcnt))
sctp_auth_shkey_destroy(sh_key);
}

void sctp_auth_shkey_hold(struct sctp_shared_key *sh_key)
{
refcount_inc(&sh_key->refcnt);
}

/* Destroy the entire key list. This is done during the
* associon and endpoint free process.
*/
Expand All @@ -128,7 +140,7 @@ void sctp_auth_destroy_keys(struct list_head *keys)

key_for_each_safe(ep_key, tmp, keys) {
list_del_init(&ep_key->key_list);
sctp_auth_shkey_free(ep_key);
sctp_auth_shkey_release(ep_key);
}
}

Expand Down Expand Up @@ -409,13 +421,19 @@ int sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp)

sctp_auth_key_put(asoc->asoc_shared_key);
asoc->asoc_shared_key = secret;
asoc->shkey = ep_key;

/* Update send queue in case any chunk already in there now
* needs authenticating
*/
list_for_each_entry(chunk, &asoc->outqueue.out_chunk_list, list) {
if (sctp_auth_send_cid(chunk->chunk_hdr->type, asoc))
if (sctp_auth_send_cid(chunk->chunk_hdr->type, asoc)) {
chunk->auth = 1;
if (!chunk->shkey) {
chunk->shkey = asoc->shkey;
sctp_auth_shkey_hold(chunk->shkey);
}
}
}

return 0;
Expand All @@ -431,8 +449,11 @@ struct sctp_shared_key *sctp_auth_get_shkey(

/* First search associations set of endpoint pair shared keys */
key_for_each(key, &asoc->endpoint_shared_keys) {
if (key->key_id == key_id)
return key;
if (key->key_id == key_id) {
if (!key->deactivated)
return key;
break;
}
}

return NULL;
Expand Down Expand Up @@ -703,16 +724,15 @@ int sctp_auth_recv_cid(enum sctp_cid chunk, const struct sctp_association *asoc)
* after the AUTH chunk in the SCTP packet.
*/
void sctp_auth_calculate_hmac(const struct sctp_association *asoc,
struct sk_buff *skb,
struct sctp_auth_chunk *auth,
gfp_t gfp)
struct sk_buff *skb, struct sctp_auth_chunk *auth,
struct sctp_shared_key *ep_key, gfp_t gfp)
{
struct crypto_shash *tfm;
struct sctp_auth_bytes *asoc_key;
struct crypto_shash *tfm;
__u16 key_id, hmac_id;
__u8 *digest;
unsigned char *end;
int free_key = 0;
__u8 *digest;

/* Extract the info we need:
* - hmac id
Expand All @@ -724,12 +744,7 @@ void sctp_auth_calculate_hmac(const struct sctp_association *asoc,
if (key_id == asoc->active_key_id)
asoc_key = asoc->asoc_shared_key;
else {
struct sctp_shared_key *ep_key;

ep_key = sctp_auth_get_shkey(asoc, key_id);
if (!ep_key)
return;

/* ep_key can't be NULL here */
asoc_key = sctp_auth_asoc_create_secret(asoc, ep_key, gfp);
if (!asoc_key)
return;
Expand Down Expand Up @@ -829,7 +844,7 @@ int sctp_auth_set_key(struct sctp_endpoint *ep,
struct sctp_association *asoc,
struct sctp_authkey *auth_key)
{
struct sctp_shared_key *cur_key = NULL;
struct sctp_shared_key *cur_key, *shkey;
struct sctp_auth_bytes *key;
struct list_head *sh_keys;
int replace = 0;
Expand All @@ -842,46 +857,34 @@ int sctp_auth_set_key(struct sctp_endpoint *ep,
else
sh_keys = &ep->endpoint_shared_keys;

key_for_each(cur_key, sh_keys) {
if (cur_key->key_id == auth_key->sca_keynumber) {
key_for_each(shkey, sh_keys) {
if (shkey->key_id == auth_key->sca_keynumber) {
replace = 1;
break;
}
}

/* If we are not replacing a key id, we need to allocate
* a shared key.
*/
if (!replace) {
cur_key = sctp_auth_shkey_create(auth_key->sca_keynumber,
GFP_KERNEL);
if (!cur_key)
return -ENOMEM;
}
cur_key = sctp_auth_shkey_create(auth_key->sca_keynumber, GFP_KERNEL);
if (!cur_key)
return -ENOMEM;

/* Create a new key data based on the info passed in */
key = sctp_auth_create_key(auth_key->sca_keylength, GFP_KERNEL);
if (!key)
goto nomem;
if (!key) {
kfree(cur_key);
return -ENOMEM;
}

memcpy(key->data, &auth_key->sca_key[0], auth_key->sca_keylength);
cur_key->key = key;

/* If we are replacing, remove the old keys data from the
* key id. If we are adding new key id, add it to the
* list.
*/
if (replace)
sctp_auth_key_put(cur_key->key);
else
list_add(&cur_key->key_list, sh_keys);
if (replace) {
list_del_init(&shkey->key_list);
sctp_auth_shkey_release(shkey);
}
list_add(&cur_key->key_list, sh_keys);

cur_key->key = key;
return 0;
nomem:
if (!replace)
sctp_auth_shkey_free(cur_key);

return -ENOMEM;
}

int sctp_auth_set_active_key(struct sctp_endpoint *ep,
Expand All @@ -905,7 +908,7 @@ int sctp_auth_set_active_key(struct sctp_endpoint *ep,
}
}

if (!found)
if (!found || key->deactivated)
return -EINVAL;

if (asoc) {
Expand Down Expand Up @@ -952,7 +955,58 @@ int sctp_auth_del_key_id(struct sctp_endpoint *ep,

/* Delete the shared key */
list_del_init(&key->key_list);
sctp_auth_shkey_free(key);
sctp_auth_shkey_release(key);

return 0;
}

int sctp_auth_deact_key_id(struct sctp_endpoint *ep,
struct sctp_association *asoc, __u16 key_id)
{
struct sctp_shared_key *key;
struct list_head *sh_keys;
int found = 0;

/* The key identifier MUST NOT be the current active key
* The key identifier MUST correst to an existing key
*/
if (asoc) {
if (asoc->active_key_id == key_id)
return -EINVAL;

sh_keys = &asoc->endpoint_shared_keys;
} else {
if (ep->active_key_id == key_id)
return -EINVAL;

sh_keys = &ep->endpoint_shared_keys;
}

key_for_each(key, sh_keys) {
if (key->key_id == key_id) {
found = 1;
break;
}
}

if (!found)
return -EINVAL;

/* refcnt == 1 and !list_empty mean it's not being used anywhere
* and deactivated will be set, so it's time to notify userland
* that this shkey can be freed.
*/
if (asoc && !list_empty(&key->key_list) &&
refcount_read(&key->refcnt) == 1) {
struct sctp_ulpevent *ev;

ev = sctp_ulpevent_make_authkey(asoc, key->key_id,
SCTP_AUTH_FREE_KEY, GFP_KERNEL);
if (ev)
asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
}

key->deactivated = 1;

return 0;
}
Loading

0 comments on commit c292566

Please sign in to comment.