aboutsummaryrefslogtreecommitdiff
path: root/net/sctp/auth.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/auth.c')
-rw-r--r--net/sctp/auth.c158
1 files changed, 83 insertions, 75 deletions
diff --git a/net/sctp/auth.c b/net/sctp/auth.c
index 78181072471..0e8529113dc 100644
--- a/net/sctp/auth.c
+++ b/net/sctp/auth.c
@@ -1,39 +1,33 @@
-/* SCTP kernel reference Implementation
+/* SCTP kernel implementation
* (C) Copyright 2007 Hewlett-Packard Development Company, L.P.
*
- * This file is part of the SCTP kernel reference Implementation
+ * This file is part of the SCTP kernel implementation
*
- * The SCTP reference implementation is free software;
+ * This SCTP implementation is free software;
* you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
- * The SCTP reference implementation is distributed in the hope that it
+ * This SCTP implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with GNU CC; see the file COPYING. If not, write to
- * the Free Software Foundation, 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * along with GNU CC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
*
* Please send any bug reports or fixes you make to the
* email address(es):
- * lksctp developers <lksctp-developers@lists.sourceforge.net>
- *
- * Or submit a bug report through the following website:
- * http://www.sf.net/projects/lksctp
+ * lksctp developers <linux-sctp@vger.kernel.org>
*
* Written or modified by:
* Vlad Yasevich <vladislav.yasevich@hp.com>
- *
- * Any bugs reported given to us we will try to fix... any fixes shared will
- * be incorporated into the next SCTP release.
*/
+#include <linux/slab.h>
#include <linux/types.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
@@ -47,18 +41,20 @@ static struct sctp_hmac sctp_hmac_list[SCTP_AUTH_NUM_HMACS] = {
},
{
.hmac_id = SCTP_AUTH_HMAC_ID_SHA1,
- .hmac_name="hmac(sha1)",
+ .hmac_name = "hmac(sha1)",
.hmac_len = SCTP_SHA1_SIG_SIZE,
},
{
/* id 2 is reserved as well */
.hmac_id = SCTP_AUTH_HMAC_ID_RESERVED_2,
},
+#if defined (CONFIG_CRYPTO_SHA256) || defined (CONFIG_CRYPTO_SHA256_MODULE)
{
.hmac_id = SCTP_AUTH_HMAC_ID_SHA256,
- .hmac_name="hmac(sha256)",
+ .hmac_name = "hmac(sha256)",
.hmac_len = SCTP_SHA256_SIG_SIZE,
}
+#endif
};
@@ -68,7 +64,7 @@ void sctp_auth_key_put(struct sctp_auth_bytes *key)
return;
if (atomic_dec_and_test(&key->refcnt)) {
- kfree(key);
+ kzfree(key);
SCTP_DBG_OBJCNT_DEC(keys);
}
}
@@ -78,6 +74,10 @@ static struct sctp_auth_bytes *sctp_auth_create_key(__u32 key_len, gfp_t gfp)
{
struct sctp_auth_bytes *key;
+ /* Verify that we are not going to overflow INT_MAX */
+ if (key_len > (INT_MAX - sizeof(struct sctp_auth_bytes)))
+ return NULL;
+
/* Allocate the shared key */
key = kmalloc(sizeof(struct sctp_auth_bytes) + key_len, gfp);
if (!key)
@@ -106,8 +106,8 @@ struct sctp_shared_key *sctp_auth_shkey_create(__u16 key_id, gfp_t gfp)
return new;
}
-/* Free the shared key stucture */
-void sctp_auth_shkey_free(struct sctp_shared_key *sh_key)
+/* Free the shared key structure */
+static void sctp_auth_shkey_free(struct sctp_shared_key *sh_key)
{
BUG_ON(!list_empty(&sh_key->key_list));
sctp_auth_key_put(sh_key->key);
@@ -115,7 +115,7 @@ void sctp_auth_shkey_free(struct sctp_shared_key *sh_key)
kfree(sh_key);
}
-/* Destory the entire key list. This is done during the
+/* Destroy the entire key list. This is done during the
* associon and endpoint free process.
*/
void sctp_auth_destroy_keys(struct list_head *keys)
@@ -135,8 +135,8 @@ void sctp_auth_destroy_keys(struct list_head *keys)
/* Compare two byte vectors as numbers. Return values
* are:
* 0 - vectors are equal
- * < 0 - vector 1 is smaller then vector2
- * > 0 - vector 1 is greater then vector2
+ * < 0 - vector 1 is smaller than vector2
+ * > 0 - vector 1 is greater than vector2
*
* Algorithm is:
* This is performed by selecting the numerically smaller key vector...
@@ -163,7 +163,7 @@ static int sctp_auth_compare_vectors(struct sctp_auth_bytes *vector1,
* lead-zero padded. If it is not, it
* is automatically larger numerically.
*/
- for (i = 0; i < abs(diff); i++ ) {
+ for (i = 0; i < abs(diff); i++) {
if (longer[i] != 0)
return diff;
}
@@ -193,46 +193,47 @@ static struct sctp_auth_bytes *sctp_auth_make_key_vector(
struct sctp_auth_bytes *new;
__u32 len;
__u32 offset = 0;
+ __u16 random_len, hmacs_len, chunks_len = 0;
- len = ntohs(random->param_hdr.length) + ntohs(hmacs->param_hdr.length);
- if (chunks)
- len += ntohs(chunks->param_hdr.length);
+ random_len = ntohs(random->param_hdr.length);
+ hmacs_len = ntohs(hmacs->param_hdr.length);
+ if (chunks)
+ chunks_len = ntohs(chunks->param_hdr.length);
- new = kmalloc(sizeof(struct sctp_auth_bytes) + len, gfp);
+ len = random_len + hmacs_len + chunks_len;
+
+ new = sctp_auth_create_key(len, gfp);
if (!new)
return NULL;
- new->len = len;
-
- memcpy(new->data, random, ntohs(random->param_hdr.length));
- offset += ntohs(random->param_hdr.length);
+ memcpy(new->data, random, random_len);
+ offset += random_len;
if (chunks) {
- memcpy(new->data + offset, chunks,
- ntohs(chunks->param_hdr.length));
- offset += ntohs(chunks->param_hdr.length);
+ memcpy(new->data + offset, chunks, chunks_len);
+ offset += chunks_len;
}
- memcpy(new->data + offset, hmacs, ntohs(hmacs->param_hdr.length));
+ memcpy(new->data + offset, hmacs, hmacs_len);
return new;
}
/* Make a key vector based on our local parameters */
-struct sctp_auth_bytes *sctp_auth_make_local_vector(
+static struct sctp_auth_bytes *sctp_auth_make_local_vector(
const struct sctp_association *asoc,
gfp_t gfp)
{
return sctp_auth_make_key_vector(
- (sctp_random_param_t*)asoc->c.auth_random,
- (sctp_chunks_param_t*)asoc->c.auth_chunks,
- (sctp_hmac_algo_param_t*)asoc->c.auth_hmacs,
+ (sctp_random_param_t *)asoc->c.auth_random,
+ (sctp_chunks_param_t *)asoc->c.auth_chunks,
+ (sctp_hmac_algo_param_t *)asoc->c.auth_hmacs,
gfp);
}
/* Make a key vector based on peer's parameters */
-struct sctp_auth_bytes *sctp_auth_make_peer_vector(
+static struct sctp_auth_bytes *sctp_auth_make_peer_vector(
const struct sctp_association *asoc,
gfp_t gfp)
{
@@ -317,7 +318,7 @@ static struct sctp_auth_bytes *sctp_auth_asoc_create_secret(
if (!peer_key_vector || !local_key_vector)
goto out;
- /* Figure out the order in wich the key_vectors will be
+ /* Figure out the order in which the key_vectors will be
* added to the endpoint shared key.
* SCTP-AUTH, Section 6.1:
* This is performed by selecting the numerically smaller key
@@ -343,8 +344,8 @@ static struct sctp_auth_bytes *sctp_auth_asoc_create_secret(
secret = sctp_auth_asoc_set_secret(ep_key, first_vector, last_vector,
gfp);
out:
- kfree(local_key_vector);
- kfree(peer_key_vector);
+ sctp_auth_key_put(local_key_vector);
+ sctp_auth_key_put(peer_key_vector);
return secret;
}
@@ -391,7 +392,7 @@ int sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp)
/* If we don't support AUTH, or peer is not capable
* we don't need to do anything.
*/
- if (!sctp_auth_enable || !asoc->peer.auth_capable)
+ if (!asoc->ep->auth_enable || !asoc->peer.auth_capable)
return 0;
/* If the key_id is non-zero and we couldn't find an
@@ -418,15 +419,15 @@ struct sctp_shared_key *sctp_auth_get_shkey(
const struct sctp_association *asoc,
__u16 key_id)
{
- struct sctp_shared_key *key = NULL;
+ struct sctp_shared_key *key;
/* First search associations set of endpoint pair shared keys */
key_for_each(key, &asoc->endpoint_shared_keys) {
if (key->key_id == key_id)
- break;
+ return key;
}
- return key;
+ return NULL;
}
/*
@@ -441,12 +442,13 @@ int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp)
struct crypto_hash *tfm = NULL;
__u16 id;
- /* if the transforms are already allocted, we are done */
- if (!sctp_auth_enable) {
+ /* If AUTH extension is disabled, we are done */
+ if (!ep->auth_enable) {
ep->auth_hmacs = NULL;
return 0;
}
+ /* If the transforms are already allocated, we are done */
if (ep->auth_hmacs)
return 0;
@@ -483,7 +485,7 @@ int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp)
return 0;
out_err:
- /* Clean up any successfull allocations */
+ /* Clean up any successful allocations */
sctp_auth_destroy_hmacs(ep->auth_hmacs);
return -ENOMEM;
}
@@ -496,8 +498,7 @@ void sctp_auth_destroy_hmacs(struct crypto_hash *auth_hmacs[])
if (!auth_hmacs)
return;
- for (i = 0; i < SCTP_AUTH_NUM_HMACS; i++)
- {
+ for (i = 0; i < SCTP_AUTH_NUM_HMACS; i++) {
if (auth_hmacs[i])
crypto_free_hash(auth_hmacs[i]);
}
@@ -535,17 +536,17 @@ struct sctp_hmac *sctp_auth_asoc_get_hmac(const struct sctp_association *asoc)
for (i = 0; i < n_elt; i++) {
id = ntohs(hmacs->hmac_ids[i]);
- /* Check the id is in the supported range */
- if (id > SCTP_AUTH_HMAC_ID_MAX)
- continue;
-
- /* See is we support the id. Supported IDs have name and
- * length fields set, so that we can allocated and use
+ /* Check the id is in the supported range. And
+ * see if we support the id. Supported IDs have name and
+ * length fields set, so that we can allocate and use
* them. We can safely just check for name, for without the
* name, we can't allocate the TFM.
*/
- if (!sctp_hmac_list[id].hmac_name)
+ if (id > SCTP_AUTH_HMAC_ID_MAX ||
+ !sctp_hmac_list[id].hmac_name) {
+ id = 0;
continue;
+ }
break;
}
@@ -556,7 +557,7 @@ struct sctp_hmac *sctp_auth_asoc_get_hmac(const struct sctp_association *asoc)
return &sctp_hmac_list[id];
}
-static int __sctp_auth_find_hmacid(__u16 *hmacs, int n_elts, __u16 hmac_id)
+static int __sctp_auth_find_hmacid(__be16 *hmacs, int n_elts, __be16 hmac_id)
{
int found = 0;
int i;
@@ -573,7 +574,7 @@ static int __sctp_auth_find_hmacid(__u16 *hmacs, int n_elts, __u16 hmac_id)
/* See if the HMAC_ID is one that we claim as supported */
int sctp_auth_asoc_verify_hmac_id(const struct sctp_association *asoc,
- __u16 hmac_id)
+ __be16 hmac_id)
{
struct sctp_hmac_algo_param *hmacs;
__u16 n_elt;
@@ -631,7 +632,7 @@ static int __sctp_auth_cid(sctp_cid_t chunk, struct sctp_chunks_param *param)
int found = 0;
int i;
- if (!param)
+ if (!param || param->param_hdr.length == 0)
return 0;
len = ntohs(param->param_hdr.length) - sizeof(sctp_paramhdr_t);
@@ -644,15 +645,15 @@ static int __sctp_auth_cid(sctp_cid_t chunk, struct sctp_chunks_param *param)
*/
for (i = 0; !found && i < len; i++) {
switch (param->chunks[i]) {
- case SCTP_CID_INIT:
- case SCTP_CID_INIT_ACK:
- case SCTP_CID_SHUTDOWN_COMPLETE:
- case SCTP_CID_AUTH:
+ case SCTP_CID_INIT:
+ case SCTP_CID_INIT_ACK:
+ case SCTP_CID_SHUTDOWN_COMPLETE:
+ case SCTP_CID_AUTH:
break;
- default:
+ default:
if (param->chunks[i] == chunk)
- found = 1;
+ found = 1;
break;
}
}
@@ -663,7 +664,10 @@ static int __sctp_auth_cid(sctp_cid_t chunk, struct sctp_chunks_param *param)
/* Check if peer requested that this chunk is authenticated */
int sctp_auth_send_cid(sctp_cid_t chunk, const struct sctp_association *asoc)
{
- if (!sctp_auth_enable || !asoc || !asoc->peer.auth_capable)
+ if (!asoc)
+ return 0;
+
+ if (!asoc->ep->auth_enable || !asoc->peer.auth_capable)
return 0;
return __sctp_auth_cid(chunk, asoc->peer.peer_chunks);
@@ -672,7 +676,10 @@ int sctp_auth_send_cid(sctp_cid_t chunk, const struct sctp_association *asoc)
/* Check if we requested that peer authenticate this chunk. */
int sctp_auth_recv_cid(sctp_cid_t chunk, const struct sctp_association *asoc)
{
- if (!sctp_auth_enable || !asoc)
+ if (!asoc)
+ return 0;
+
+ if (!asoc->ep->auth_enable)
return 0;
return __sctp_auth_cid(chunk,
@@ -726,9 +733,7 @@ void sctp_auth_calculate_hmac(const struct sctp_association *asoc,
/* set up scatter list */
end = skb_tail_pointer(skb);
- sg.page = virt_to_page(auth);
- sg.offset = (unsigned long)(auth) % PAGE_SIZE;
- sg.length = end - (unsigned char *)auth;
+ sg_init_one(&sg, auth, end - (unsigned char *)auth);
desc.tfm = asoc->ep->auth_hmacs[hmac_id];
desc.flags = 0;
@@ -782,6 +787,9 @@ int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep,
for (i = 0; i < hmacs->shmac_num_idents; i++) {
id = hmacs->shmac_idents[i];
+ if (id > SCTP_AUTH_HMAC_ID_MAX)
+ return -EOPNOTSUPP;
+
if (SCTP_AUTH_HMAC_ID_SHA1 == id)
has_sha1 = 1;
@@ -838,11 +846,11 @@ int sctp_auth_set_key(struct sctp_endpoint *ep,
}
/* Create a new key data based on the info passed in */
- key = sctp_auth_create_key(auth_key->sca_keylen, GFP_KERNEL);
+ key = sctp_auth_create_key(auth_key->sca_keylength, GFP_KERNEL);
if (!key)
goto nomem;
- memcpy(key->data, &auth_key->sca_key[0], auth_key->sca_keylen);
+ memcpy(key->data, &auth_key->sca_key[0], auth_key->sca_keylength);
/* If we are replacing, remove the old keys data from the
* key id. If we are adding new key id, add it to the