162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* SCTP kernel implementation 362306a36Sopenharmony_ci * (C) Copyright 2007 Hewlett-Packard Development Company, L.P. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This file is part of the SCTP kernel implementation 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Please send any bug reports or fixes you make to the 862306a36Sopenharmony_ci * email address(es): 962306a36Sopenharmony_ci * lksctp developers <linux-sctp@vger.kernel.org> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Written or modified by: 1262306a36Sopenharmony_ci * Vlad Yasevich <vladislav.yasevich@hp.com> 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <crypto/hash.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/types.h> 1862306a36Sopenharmony_ci#include <linux/scatterlist.h> 1962306a36Sopenharmony_ci#include <net/sctp/sctp.h> 2062306a36Sopenharmony_ci#include <net/sctp/auth.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic struct sctp_hmac sctp_hmac_list[SCTP_AUTH_NUM_HMACS] = { 2362306a36Sopenharmony_ci { 2462306a36Sopenharmony_ci /* id 0 is reserved. as all 0 */ 2562306a36Sopenharmony_ci .hmac_id = SCTP_AUTH_HMAC_ID_RESERVED_0, 2662306a36Sopenharmony_ci }, 2762306a36Sopenharmony_ci { 2862306a36Sopenharmony_ci .hmac_id = SCTP_AUTH_HMAC_ID_SHA1, 2962306a36Sopenharmony_ci .hmac_name = "hmac(sha1)", 3062306a36Sopenharmony_ci .hmac_len = SCTP_SHA1_SIG_SIZE, 3162306a36Sopenharmony_ci }, 3262306a36Sopenharmony_ci { 3362306a36Sopenharmony_ci /* id 2 is reserved as well */ 3462306a36Sopenharmony_ci .hmac_id = SCTP_AUTH_HMAC_ID_RESERVED_2, 3562306a36Sopenharmony_ci }, 3662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_CRYPTO_SHA256) 3762306a36Sopenharmony_ci { 3862306a36Sopenharmony_ci .hmac_id = SCTP_AUTH_HMAC_ID_SHA256, 3962306a36Sopenharmony_ci .hmac_name = "hmac(sha256)", 4062306a36Sopenharmony_ci .hmac_len = SCTP_SHA256_SIG_SIZE, 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci#endif 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_civoid sctp_auth_key_put(struct sctp_auth_bytes *key) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci if (!key) 4962306a36Sopenharmony_ci return; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (refcount_dec_and_test(&key->refcnt)) { 5262306a36Sopenharmony_ci kfree_sensitive(key); 5362306a36Sopenharmony_ci SCTP_DBG_OBJCNT_DEC(keys); 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* Create a new key structure of a given length */ 5862306a36Sopenharmony_cistatic struct sctp_auth_bytes *sctp_auth_create_key(__u32 key_len, gfp_t gfp) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct sctp_auth_bytes *key; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* Verify that we are not going to overflow INT_MAX */ 6362306a36Sopenharmony_ci if (key_len > (INT_MAX - sizeof(struct sctp_auth_bytes))) 6462306a36Sopenharmony_ci return NULL; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* Allocate the shared key */ 6762306a36Sopenharmony_ci key = kmalloc(sizeof(struct sctp_auth_bytes) + key_len, gfp); 6862306a36Sopenharmony_ci if (!key) 6962306a36Sopenharmony_ci return NULL; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci key->len = key_len; 7262306a36Sopenharmony_ci refcount_set(&key->refcnt, 1); 7362306a36Sopenharmony_ci SCTP_DBG_OBJCNT_INC(keys); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return key; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* Create a new shared key container with a give key id */ 7962306a36Sopenharmony_cistruct sctp_shared_key *sctp_auth_shkey_create(__u16 key_id, gfp_t gfp) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct sctp_shared_key *new; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* Allocate the shared key container */ 8462306a36Sopenharmony_ci new = kzalloc(sizeof(struct sctp_shared_key), gfp); 8562306a36Sopenharmony_ci if (!new) 8662306a36Sopenharmony_ci return NULL; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci INIT_LIST_HEAD(&new->key_list); 8962306a36Sopenharmony_ci refcount_set(&new->refcnt, 1); 9062306a36Sopenharmony_ci new->key_id = key_id; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return new; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/* Free the shared key structure */ 9662306a36Sopenharmony_cistatic void sctp_auth_shkey_destroy(struct sctp_shared_key *sh_key) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci BUG_ON(!list_empty(&sh_key->key_list)); 9962306a36Sopenharmony_ci sctp_auth_key_put(sh_key->key); 10062306a36Sopenharmony_ci sh_key->key = NULL; 10162306a36Sopenharmony_ci kfree(sh_key); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_civoid sctp_auth_shkey_release(struct sctp_shared_key *sh_key) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci if (refcount_dec_and_test(&sh_key->refcnt)) 10762306a36Sopenharmony_ci sctp_auth_shkey_destroy(sh_key); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_civoid sctp_auth_shkey_hold(struct sctp_shared_key *sh_key) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci refcount_inc(&sh_key->refcnt); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/* Destroy the entire key list. This is done during the 11662306a36Sopenharmony_ci * associon and endpoint free process. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_civoid sctp_auth_destroy_keys(struct list_head *keys) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct sctp_shared_key *ep_key; 12162306a36Sopenharmony_ci struct sctp_shared_key *tmp; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (list_empty(keys)) 12462306a36Sopenharmony_ci return; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci key_for_each_safe(ep_key, tmp, keys) { 12762306a36Sopenharmony_ci list_del_init(&ep_key->key_list); 12862306a36Sopenharmony_ci sctp_auth_shkey_release(ep_key); 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* Compare two byte vectors as numbers. Return values 13362306a36Sopenharmony_ci * are: 13462306a36Sopenharmony_ci * 0 - vectors are equal 13562306a36Sopenharmony_ci * < 0 - vector 1 is smaller than vector2 13662306a36Sopenharmony_ci * > 0 - vector 1 is greater than vector2 13762306a36Sopenharmony_ci * 13862306a36Sopenharmony_ci * Algorithm is: 13962306a36Sopenharmony_ci * This is performed by selecting the numerically smaller key vector... 14062306a36Sopenharmony_ci * If the key vectors are equal as numbers but differ in length ... 14162306a36Sopenharmony_ci * the shorter vector is considered smaller 14262306a36Sopenharmony_ci * 14362306a36Sopenharmony_ci * Examples (with small values): 14462306a36Sopenharmony_ci * 000123456789 > 123456789 (first number is longer) 14562306a36Sopenharmony_ci * 000123456789 < 234567891 (second number is larger numerically) 14662306a36Sopenharmony_ci * 123456789 > 2345678 (first number is both larger & longer) 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_cistatic int sctp_auth_compare_vectors(struct sctp_auth_bytes *vector1, 14962306a36Sopenharmony_ci struct sctp_auth_bytes *vector2) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci int diff; 15262306a36Sopenharmony_ci int i; 15362306a36Sopenharmony_ci const __u8 *longer; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci diff = vector1->len - vector2->len; 15662306a36Sopenharmony_ci if (diff) { 15762306a36Sopenharmony_ci longer = (diff > 0) ? vector1->data : vector2->data; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* Check to see if the longer number is 16062306a36Sopenharmony_ci * lead-zero padded. If it is not, it 16162306a36Sopenharmony_ci * is automatically larger numerically. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ci for (i = 0; i < abs(diff); i++) { 16462306a36Sopenharmony_ci if (longer[i] != 0) 16562306a36Sopenharmony_ci return diff; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* lengths are the same, compare numbers */ 17062306a36Sopenharmony_ci return memcmp(vector1->data, vector2->data, vector1->len); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci/* 17462306a36Sopenharmony_ci * Create a key vector as described in SCTP-AUTH, Section 6.1 17562306a36Sopenharmony_ci * The RANDOM parameter, the CHUNKS parameter and the HMAC-ALGO 17662306a36Sopenharmony_ci * parameter sent by each endpoint are concatenated as byte vectors. 17762306a36Sopenharmony_ci * These parameters include the parameter type, parameter length, and 17862306a36Sopenharmony_ci * the parameter value, but padding is omitted; all padding MUST be 17962306a36Sopenharmony_ci * removed from this concatenation before proceeding with further 18062306a36Sopenharmony_ci * computation of keys. Parameters which were not sent are simply 18162306a36Sopenharmony_ci * omitted from the concatenation process. The resulting two vectors 18262306a36Sopenharmony_ci * are called the two key vectors. 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_cistatic struct sctp_auth_bytes *sctp_auth_make_key_vector( 18562306a36Sopenharmony_ci struct sctp_random_param *random, 18662306a36Sopenharmony_ci struct sctp_chunks_param *chunks, 18762306a36Sopenharmony_ci struct sctp_hmac_algo_param *hmacs, 18862306a36Sopenharmony_ci gfp_t gfp) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct sctp_auth_bytes *new; 19162306a36Sopenharmony_ci __u32 len; 19262306a36Sopenharmony_ci __u32 offset = 0; 19362306a36Sopenharmony_ci __u16 random_len, hmacs_len, chunks_len = 0; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci random_len = ntohs(random->param_hdr.length); 19662306a36Sopenharmony_ci hmacs_len = ntohs(hmacs->param_hdr.length); 19762306a36Sopenharmony_ci if (chunks) 19862306a36Sopenharmony_ci chunks_len = ntohs(chunks->param_hdr.length); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci len = random_len + hmacs_len + chunks_len; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci new = sctp_auth_create_key(len, gfp); 20362306a36Sopenharmony_ci if (!new) 20462306a36Sopenharmony_ci return NULL; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci memcpy(new->data, random, random_len); 20762306a36Sopenharmony_ci offset += random_len; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (chunks) { 21062306a36Sopenharmony_ci memcpy(new->data + offset, chunks, chunks_len); 21162306a36Sopenharmony_ci offset += chunks_len; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci memcpy(new->data + offset, hmacs, hmacs_len); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci return new; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci/* Make a key vector based on our local parameters */ 22162306a36Sopenharmony_cistatic struct sctp_auth_bytes *sctp_auth_make_local_vector( 22262306a36Sopenharmony_ci const struct sctp_association *asoc, 22362306a36Sopenharmony_ci gfp_t gfp) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci return sctp_auth_make_key_vector( 22662306a36Sopenharmony_ci (struct sctp_random_param *)asoc->c.auth_random, 22762306a36Sopenharmony_ci (struct sctp_chunks_param *)asoc->c.auth_chunks, 22862306a36Sopenharmony_ci (struct sctp_hmac_algo_param *)asoc->c.auth_hmacs, gfp); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/* Make a key vector based on peer's parameters */ 23262306a36Sopenharmony_cistatic struct sctp_auth_bytes *sctp_auth_make_peer_vector( 23362306a36Sopenharmony_ci const struct sctp_association *asoc, 23462306a36Sopenharmony_ci gfp_t gfp) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci return sctp_auth_make_key_vector(asoc->peer.peer_random, 23762306a36Sopenharmony_ci asoc->peer.peer_chunks, 23862306a36Sopenharmony_ci asoc->peer.peer_hmacs, 23962306a36Sopenharmony_ci gfp); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/* Set the value of the association shared key base on the parameters 24462306a36Sopenharmony_ci * given. The algorithm is: 24562306a36Sopenharmony_ci * From the endpoint pair shared keys and the key vectors the 24662306a36Sopenharmony_ci * association shared keys are computed. This is performed by selecting 24762306a36Sopenharmony_ci * the numerically smaller key vector and concatenating it to the 24862306a36Sopenharmony_ci * endpoint pair shared key, and then concatenating the numerically 24962306a36Sopenharmony_ci * larger key vector to that. The result of the concatenation is the 25062306a36Sopenharmony_ci * association shared key. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_cistatic struct sctp_auth_bytes *sctp_auth_asoc_set_secret( 25362306a36Sopenharmony_ci struct sctp_shared_key *ep_key, 25462306a36Sopenharmony_ci struct sctp_auth_bytes *first_vector, 25562306a36Sopenharmony_ci struct sctp_auth_bytes *last_vector, 25662306a36Sopenharmony_ci gfp_t gfp) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci struct sctp_auth_bytes *secret; 25962306a36Sopenharmony_ci __u32 offset = 0; 26062306a36Sopenharmony_ci __u32 auth_len; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci auth_len = first_vector->len + last_vector->len; 26362306a36Sopenharmony_ci if (ep_key->key) 26462306a36Sopenharmony_ci auth_len += ep_key->key->len; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci secret = sctp_auth_create_key(auth_len, gfp); 26762306a36Sopenharmony_ci if (!secret) 26862306a36Sopenharmony_ci return NULL; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (ep_key->key) { 27162306a36Sopenharmony_ci memcpy(secret->data, ep_key->key->data, ep_key->key->len); 27262306a36Sopenharmony_ci offset += ep_key->key->len; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci memcpy(secret->data + offset, first_vector->data, first_vector->len); 27662306a36Sopenharmony_ci offset += first_vector->len; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci memcpy(secret->data + offset, last_vector->data, last_vector->len); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci return secret; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/* Create an association shared key. Follow the algorithm 28462306a36Sopenharmony_ci * described in SCTP-AUTH, Section 6.1 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_cistatic struct sctp_auth_bytes *sctp_auth_asoc_create_secret( 28762306a36Sopenharmony_ci const struct sctp_association *asoc, 28862306a36Sopenharmony_ci struct sctp_shared_key *ep_key, 28962306a36Sopenharmony_ci gfp_t gfp) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci struct sctp_auth_bytes *local_key_vector; 29262306a36Sopenharmony_ci struct sctp_auth_bytes *peer_key_vector; 29362306a36Sopenharmony_ci struct sctp_auth_bytes *first_vector, 29462306a36Sopenharmony_ci *last_vector; 29562306a36Sopenharmony_ci struct sctp_auth_bytes *secret = NULL; 29662306a36Sopenharmony_ci int cmp; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* Now we need to build the key vectors 30062306a36Sopenharmony_ci * SCTP-AUTH , Section 6.1 30162306a36Sopenharmony_ci * The RANDOM parameter, the CHUNKS parameter and the HMAC-ALGO 30262306a36Sopenharmony_ci * parameter sent by each endpoint are concatenated as byte vectors. 30362306a36Sopenharmony_ci * These parameters include the parameter type, parameter length, and 30462306a36Sopenharmony_ci * the parameter value, but padding is omitted; all padding MUST be 30562306a36Sopenharmony_ci * removed from this concatenation before proceeding with further 30662306a36Sopenharmony_ci * computation of keys. Parameters which were not sent are simply 30762306a36Sopenharmony_ci * omitted from the concatenation process. The resulting two vectors 30862306a36Sopenharmony_ci * are called the two key vectors. 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci local_key_vector = sctp_auth_make_local_vector(asoc, gfp); 31262306a36Sopenharmony_ci peer_key_vector = sctp_auth_make_peer_vector(asoc, gfp); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (!peer_key_vector || !local_key_vector) 31562306a36Sopenharmony_ci goto out; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* Figure out the order in which the key_vectors will be 31862306a36Sopenharmony_ci * added to the endpoint shared key. 31962306a36Sopenharmony_ci * SCTP-AUTH, Section 6.1: 32062306a36Sopenharmony_ci * This is performed by selecting the numerically smaller key 32162306a36Sopenharmony_ci * vector and concatenating it to the endpoint pair shared 32262306a36Sopenharmony_ci * key, and then concatenating the numerically larger key 32362306a36Sopenharmony_ci * vector to that. If the key vectors are equal as numbers 32462306a36Sopenharmony_ci * but differ in length, then the concatenation order is the 32562306a36Sopenharmony_ci * endpoint shared key, followed by the shorter key vector, 32662306a36Sopenharmony_ci * followed by the longer key vector. Otherwise, the key 32762306a36Sopenharmony_ci * vectors are identical, and may be concatenated to the 32862306a36Sopenharmony_ci * endpoint pair key in any order. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_ci cmp = sctp_auth_compare_vectors(local_key_vector, 33162306a36Sopenharmony_ci peer_key_vector); 33262306a36Sopenharmony_ci if (cmp < 0) { 33362306a36Sopenharmony_ci first_vector = local_key_vector; 33462306a36Sopenharmony_ci last_vector = peer_key_vector; 33562306a36Sopenharmony_ci } else { 33662306a36Sopenharmony_ci first_vector = peer_key_vector; 33762306a36Sopenharmony_ci last_vector = local_key_vector; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci secret = sctp_auth_asoc_set_secret(ep_key, first_vector, last_vector, 34162306a36Sopenharmony_ci gfp); 34262306a36Sopenharmony_ciout: 34362306a36Sopenharmony_ci sctp_auth_key_put(local_key_vector); 34462306a36Sopenharmony_ci sctp_auth_key_put(peer_key_vector); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci return secret; 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/* 35062306a36Sopenharmony_ci * Populate the association overlay list with the list 35162306a36Sopenharmony_ci * from the endpoint. 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ciint sctp_auth_asoc_copy_shkeys(const struct sctp_endpoint *ep, 35462306a36Sopenharmony_ci struct sctp_association *asoc, 35562306a36Sopenharmony_ci gfp_t gfp) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct sctp_shared_key *sh_key; 35862306a36Sopenharmony_ci struct sctp_shared_key *new; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci BUG_ON(!list_empty(&asoc->endpoint_shared_keys)); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci key_for_each(sh_key, &ep->endpoint_shared_keys) { 36362306a36Sopenharmony_ci new = sctp_auth_shkey_create(sh_key->key_id, gfp); 36462306a36Sopenharmony_ci if (!new) 36562306a36Sopenharmony_ci goto nomem; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci new->key = sh_key->key; 36862306a36Sopenharmony_ci sctp_auth_key_hold(new->key); 36962306a36Sopenharmony_ci list_add(&new->key_list, &asoc->endpoint_shared_keys); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return 0; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cinomem: 37562306a36Sopenharmony_ci sctp_auth_destroy_keys(&asoc->endpoint_shared_keys); 37662306a36Sopenharmony_ci return -ENOMEM; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci/* Public interface to create the association shared key. 38162306a36Sopenharmony_ci * See code above for the algorithm. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ciint sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct sctp_auth_bytes *secret; 38662306a36Sopenharmony_ci struct sctp_shared_key *ep_key; 38762306a36Sopenharmony_ci struct sctp_chunk *chunk; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* If we don't support AUTH, or peer is not capable 39062306a36Sopenharmony_ci * we don't need to do anything. 39162306a36Sopenharmony_ci */ 39262306a36Sopenharmony_ci if (!asoc->peer.auth_capable) 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* If the key_id is non-zero and we couldn't find an 39662306a36Sopenharmony_ci * endpoint pair shared key, we can't compute the 39762306a36Sopenharmony_ci * secret. 39862306a36Sopenharmony_ci * For key_id 0, endpoint pair shared key is a NULL key. 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_ci ep_key = sctp_auth_get_shkey(asoc, asoc->active_key_id); 40162306a36Sopenharmony_ci BUG_ON(!ep_key); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci secret = sctp_auth_asoc_create_secret(asoc, ep_key, gfp); 40462306a36Sopenharmony_ci if (!secret) 40562306a36Sopenharmony_ci return -ENOMEM; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci sctp_auth_key_put(asoc->asoc_shared_key); 40862306a36Sopenharmony_ci asoc->asoc_shared_key = secret; 40962306a36Sopenharmony_ci asoc->shkey = ep_key; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* Update send queue in case any chunk already in there now 41262306a36Sopenharmony_ci * needs authenticating 41362306a36Sopenharmony_ci */ 41462306a36Sopenharmony_ci list_for_each_entry(chunk, &asoc->outqueue.out_chunk_list, list) { 41562306a36Sopenharmony_ci if (sctp_auth_send_cid(chunk->chunk_hdr->type, asoc)) { 41662306a36Sopenharmony_ci chunk->auth = 1; 41762306a36Sopenharmony_ci if (!chunk->shkey) { 41862306a36Sopenharmony_ci chunk->shkey = asoc->shkey; 41962306a36Sopenharmony_ci sctp_auth_shkey_hold(chunk->shkey); 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci return 0; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci/* Find the endpoint pair shared key based on the key_id */ 42962306a36Sopenharmony_cistruct sctp_shared_key *sctp_auth_get_shkey( 43062306a36Sopenharmony_ci const struct sctp_association *asoc, 43162306a36Sopenharmony_ci __u16 key_id) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct sctp_shared_key *key; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* First search associations set of endpoint pair shared keys */ 43662306a36Sopenharmony_ci key_for_each(key, &asoc->endpoint_shared_keys) { 43762306a36Sopenharmony_ci if (key->key_id == key_id) { 43862306a36Sopenharmony_ci if (!key->deactivated) 43962306a36Sopenharmony_ci return key; 44062306a36Sopenharmony_ci break; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci return NULL; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci/* 44862306a36Sopenharmony_ci * Initialize all the possible digest transforms that we can use. Right 44962306a36Sopenharmony_ci * now, the supported digests are SHA1 and SHA256. We do this here once 45062306a36Sopenharmony_ci * because of the restrictiong that transforms may only be allocated in 45162306a36Sopenharmony_ci * user context. This forces us to pre-allocated all possible transforms 45262306a36Sopenharmony_ci * at the endpoint init time. 45362306a36Sopenharmony_ci */ 45462306a36Sopenharmony_ciint sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci struct crypto_shash *tfm = NULL; 45762306a36Sopenharmony_ci __u16 id; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* If the transforms are already allocated, we are done */ 46062306a36Sopenharmony_ci if (ep->auth_hmacs) 46162306a36Sopenharmony_ci return 0; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* Allocated the array of pointers to transorms */ 46462306a36Sopenharmony_ci ep->auth_hmacs = kcalloc(SCTP_AUTH_NUM_HMACS, 46562306a36Sopenharmony_ci sizeof(struct crypto_shash *), 46662306a36Sopenharmony_ci gfp); 46762306a36Sopenharmony_ci if (!ep->auth_hmacs) 46862306a36Sopenharmony_ci return -ENOMEM; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci for (id = 0; id < SCTP_AUTH_NUM_HMACS; id++) { 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci /* See is we support the id. Supported IDs have name and 47362306a36Sopenharmony_ci * length fields set, so that we can allocated and use 47462306a36Sopenharmony_ci * them. We can safely just check for name, for without the 47562306a36Sopenharmony_ci * name, we can't allocate the TFM. 47662306a36Sopenharmony_ci */ 47762306a36Sopenharmony_ci if (!sctp_hmac_list[id].hmac_name) 47862306a36Sopenharmony_ci continue; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* If this TFM has been allocated, we are all set */ 48162306a36Sopenharmony_ci if (ep->auth_hmacs[id]) 48262306a36Sopenharmony_ci continue; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* Allocate the ID */ 48562306a36Sopenharmony_ci tfm = crypto_alloc_shash(sctp_hmac_list[id].hmac_name, 0, 0); 48662306a36Sopenharmony_ci if (IS_ERR(tfm)) 48762306a36Sopenharmony_ci goto out_err; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci ep->auth_hmacs[id] = tfm; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci return 0; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ciout_err: 49562306a36Sopenharmony_ci /* Clean up any successful allocations */ 49662306a36Sopenharmony_ci sctp_auth_destroy_hmacs(ep->auth_hmacs); 49762306a36Sopenharmony_ci ep->auth_hmacs = NULL; 49862306a36Sopenharmony_ci return -ENOMEM; 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci/* Destroy the hmac tfm array */ 50262306a36Sopenharmony_civoid sctp_auth_destroy_hmacs(struct crypto_shash *auth_hmacs[]) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci int i; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (!auth_hmacs) 50762306a36Sopenharmony_ci return; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci for (i = 0; i < SCTP_AUTH_NUM_HMACS; i++) { 51062306a36Sopenharmony_ci crypto_free_shash(auth_hmacs[i]); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci kfree(auth_hmacs); 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistruct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci return &sctp_hmac_list[hmac_id]; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci/* Get an hmac description information that we can use to build 52262306a36Sopenharmony_ci * the AUTH chunk 52362306a36Sopenharmony_ci */ 52462306a36Sopenharmony_cistruct sctp_hmac *sctp_auth_asoc_get_hmac(const struct sctp_association *asoc) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci struct sctp_hmac_algo_param *hmacs; 52762306a36Sopenharmony_ci __u16 n_elt; 52862306a36Sopenharmony_ci __u16 id = 0; 52962306a36Sopenharmony_ci int i; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* If we have a default entry, use it */ 53262306a36Sopenharmony_ci if (asoc->default_hmac_id) 53362306a36Sopenharmony_ci return &sctp_hmac_list[asoc->default_hmac_id]; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci /* Since we do not have a default entry, find the first entry 53662306a36Sopenharmony_ci * we support and return that. Do not cache that id. 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_ci hmacs = asoc->peer.peer_hmacs; 53962306a36Sopenharmony_ci if (!hmacs) 54062306a36Sopenharmony_ci return NULL; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci n_elt = (ntohs(hmacs->param_hdr.length) - 54362306a36Sopenharmony_ci sizeof(struct sctp_paramhdr)) >> 1; 54462306a36Sopenharmony_ci for (i = 0; i < n_elt; i++) { 54562306a36Sopenharmony_ci id = ntohs(hmacs->hmac_ids[i]); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* Check the id is in the supported range. And 54862306a36Sopenharmony_ci * see if we support the id. Supported IDs have name and 54962306a36Sopenharmony_ci * length fields set, so that we can allocate and use 55062306a36Sopenharmony_ci * them. We can safely just check for name, for without the 55162306a36Sopenharmony_ci * name, we can't allocate the TFM. 55262306a36Sopenharmony_ci */ 55362306a36Sopenharmony_ci if (id > SCTP_AUTH_HMAC_ID_MAX || 55462306a36Sopenharmony_ci !sctp_hmac_list[id].hmac_name) { 55562306a36Sopenharmony_ci id = 0; 55662306a36Sopenharmony_ci continue; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci break; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (id == 0) 56362306a36Sopenharmony_ci return NULL; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci return &sctp_hmac_list[id]; 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic int __sctp_auth_find_hmacid(__be16 *hmacs, int n_elts, __be16 hmac_id) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci int found = 0; 57162306a36Sopenharmony_ci int i; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci for (i = 0; i < n_elts; i++) { 57462306a36Sopenharmony_ci if (hmac_id == hmacs[i]) { 57562306a36Sopenharmony_ci found = 1; 57662306a36Sopenharmony_ci break; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci return found; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci/* See if the HMAC_ID is one that we claim as supported */ 58462306a36Sopenharmony_ciint sctp_auth_asoc_verify_hmac_id(const struct sctp_association *asoc, 58562306a36Sopenharmony_ci __be16 hmac_id) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci struct sctp_hmac_algo_param *hmacs; 58862306a36Sopenharmony_ci __u16 n_elt; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (!asoc) 59162306a36Sopenharmony_ci return 0; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci hmacs = (struct sctp_hmac_algo_param *)asoc->c.auth_hmacs; 59462306a36Sopenharmony_ci n_elt = (ntohs(hmacs->param_hdr.length) - 59562306a36Sopenharmony_ci sizeof(struct sctp_paramhdr)) >> 1; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return __sctp_auth_find_hmacid(hmacs->hmac_ids, n_elt, hmac_id); 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci/* Cache the default HMAC id. This to follow this text from SCTP-AUTH: 60262306a36Sopenharmony_ci * Section 6.1: 60362306a36Sopenharmony_ci * The receiver of a HMAC-ALGO parameter SHOULD use the first listed 60462306a36Sopenharmony_ci * algorithm it supports. 60562306a36Sopenharmony_ci */ 60662306a36Sopenharmony_civoid sctp_auth_asoc_set_default_hmac(struct sctp_association *asoc, 60762306a36Sopenharmony_ci struct sctp_hmac_algo_param *hmacs) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci struct sctp_endpoint *ep; 61062306a36Sopenharmony_ci __u16 id; 61162306a36Sopenharmony_ci int i; 61262306a36Sopenharmony_ci int n_params; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci /* if the default id is already set, use it */ 61562306a36Sopenharmony_ci if (asoc->default_hmac_id) 61662306a36Sopenharmony_ci return; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci n_params = (ntohs(hmacs->param_hdr.length) - 61962306a36Sopenharmony_ci sizeof(struct sctp_paramhdr)) >> 1; 62062306a36Sopenharmony_ci ep = asoc->ep; 62162306a36Sopenharmony_ci for (i = 0; i < n_params; i++) { 62262306a36Sopenharmony_ci id = ntohs(hmacs->hmac_ids[i]); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* Check the id is in the supported range */ 62562306a36Sopenharmony_ci if (id > SCTP_AUTH_HMAC_ID_MAX) 62662306a36Sopenharmony_ci continue; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci /* If this TFM has been allocated, use this id */ 62962306a36Sopenharmony_ci if (ep->auth_hmacs[id]) { 63062306a36Sopenharmony_ci asoc->default_hmac_id = id; 63162306a36Sopenharmony_ci break; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci/* Check to see if the given chunk is supposed to be authenticated */ 63862306a36Sopenharmony_cistatic int __sctp_auth_cid(enum sctp_cid chunk, struct sctp_chunks_param *param) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci unsigned short len; 64162306a36Sopenharmony_ci int found = 0; 64262306a36Sopenharmony_ci int i; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (!param || param->param_hdr.length == 0) 64562306a36Sopenharmony_ci return 0; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci len = ntohs(param->param_hdr.length) - sizeof(struct sctp_paramhdr); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* SCTP-AUTH, Section 3.2 65062306a36Sopenharmony_ci * The chunk types for INIT, INIT-ACK, SHUTDOWN-COMPLETE and AUTH 65162306a36Sopenharmony_ci * chunks MUST NOT be listed in the CHUNKS parameter. However, if 65262306a36Sopenharmony_ci * a CHUNKS parameter is received then the types for INIT, INIT-ACK, 65362306a36Sopenharmony_ci * SHUTDOWN-COMPLETE and AUTH chunks MUST be ignored. 65462306a36Sopenharmony_ci */ 65562306a36Sopenharmony_ci for (i = 0; !found && i < len; i++) { 65662306a36Sopenharmony_ci switch (param->chunks[i]) { 65762306a36Sopenharmony_ci case SCTP_CID_INIT: 65862306a36Sopenharmony_ci case SCTP_CID_INIT_ACK: 65962306a36Sopenharmony_ci case SCTP_CID_SHUTDOWN_COMPLETE: 66062306a36Sopenharmony_ci case SCTP_CID_AUTH: 66162306a36Sopenharmony_ci break; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci default: 66462306a36Sopenharmony_ci if (param->chunks[i] == chunk) 66562306a36Sopenharmony_ci found = 1; 66662306a36Sopenharmony_ci break; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci return found; 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci/* Check if peer requested that this chunk is authenticated */ 67462306a36Sopenharmony_ciint sctp_auth_send_cid(enum sctp_cid chunk, const struct sctp_association *asoc) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci if (!asoc) 67762306a36Sopenharmony_ci return 0; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (!asoc->peer.auth_capable) 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci return __sctp_auth_cid(chunk, asoc->peer.peer_chunks); 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci/* Check if we requested that peer authenticate this chunk. */ 68662306a36Sopenharmony_ciint sctp_auth_recv_cid(enum sctp_cid chunk, const struct sctp_association *asoc) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci if (!asoc) 68962306a36Sopenharmony_ci return 0; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (!asoc->peer.auth_capable) 69262306a36Sopenharmony_ci return 0; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci return __sctp_auth_cid(chunk, 69562306a36Sopenharmony_ci (struct sctp_chunks_param *)asoc->c.auth_chunks); 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci/* SCTP-AUTH: Section 6.2: 69962306a36Sopenharmony_ci * The sender MUST calculate the MAC as described in RFC2104 [2] using 70062306a36Sopenharmony_ci * the hash function H as described by the MAC Identifier and the shared 70162306a36Sopenharmony_ci * association key K based on the endpoint pair shared key described by 70262306a36Sopenharmony_ci * the shared key identifier. The 'data' used for the computation of 70362306a36Sopenharmony_ci * the AUTH-chunk is given by the AUTH chunk with its HMAC field set to 70462306a36Sopenharmony_ci * zero (as shown in Figure 6) followed by all chunks that are placed 70562306a36Sopenharmony_ci * after the AUTH chunk in the SCTP packet. 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_civoid sctp_auth_calculate_hmac(const struct sctp_association *asoc, 70862306a36Sopenharmony_ci struct sk_buff *skb, struct sctp_auth_chunk *auth, 70962306a36Sopenharmony_ci struct sctp_shared_key *ep_key, gfp_t gfp) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci struct sctp_auth_bytes *asoc_key; 71262306a36Sopenharmony_ci struct crypto_shash *tfm; 71362306a36Sopenharmony_ci __u16 key_id, hmac_id; 71462306a36Sopenharmony_ci unsigned char *end; 71562306a36Sopenharmony_ci int free_key = 0; 71662306a36Sopenharmony_ci __u8 *digest; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* Extract the info we need: 71962306a36Sopenharmony_ci * - hmac id 72062306a36Sopenharmony_ci * - key id 72162306a36Sopenharmony_ci */ 72262306a36Sopenharmony_ci key_id = ntohs(auth->auth_hdr.shkey_id); 72362306a36Sopenharmony_ci hmac_id = ntohs(auth->auth_hdr.hmac_id); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (key_id == asoc->active_key_id) 72662306a36Sopenharmony_ci asoc_key = asoc->asoc_shared_key; 72762306a36Sopenharmony_ci else { 72862306a36Sopenharmony_ci /* ep_key can't be NULL here */ 72962306a36Sopenharmony_ci asoc_key = sctp_auth_asoc_create_secret(asoc, ep_key, gfp); 73062306a36Sopenharmony_ci if (!asoc_key) 73162306a36Sopenharmony_ci return; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci free_key = 1; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* set up scatter list */ 73762306a36Sopenharmony_ci end = skb_tail_pointer(skb); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci tfm = asoc->ep->auth_hmacs[hmac_id]; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci digest = (u8 *)(&auth->auth_hdr + 1); 74262306a36Sopenharmony_ci if (crypto_shash_setkey(tfm, &asoc_key->data[0], asoc_key->len)) 74362306a36Sopenharmony_ci goto free; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci crypto_shash_tfm_digest(tfm, (u8 *)auth, end - (unsigned char *)auth, 74662306a36Sopenharmony_ci digest); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_cifree: 74962306a36Sopenharmony_ci if (free_key) 75062306a36Sopenharmony_ci sctp_auth_key_put(asoc_key); 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci/* API Helpers */ 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci/* Add a chunk to the endpoint authenticated chunk list */ 75662306a36Sopenharmony_ciint sctp_auth_ep_add_chunkid(struct sctp_endpoint *ep, __u8 chunk_id) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci struct sctp_chunks_param *p = ep->auth_chunk_list; 75962306a36Sopenharmony_ci __u16 nchunks; 76062306a36Sopenharmony_ci __u16 param_len; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci /* If this chunk is already specified, we are done */ 76362306a36Sopenharmony_ci if (__sctp_auth_cid(chunk_id, p)) 76462306a36Sopenharmony_ci return 0; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* Check if we can add this chunk to the array */ 76762306a36Sopenharmony_ci param_len = ntohs(p->param_hdr.length); 76862306a36Sopenharmony_ci nchunks = param_len - sizeof(struct sctp_paramhdr); 76962306a36Sopenharmony_ci if (nchunks == SCTP_NUM_CHUNK_TYPES) 77062306a36Sopenharmony_ci return -EINVAL; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci p->chunks[nchunks] = chunk_id; 77362306a36Sopenharmony_ci p->param_hdr.length = htons(param_len + 1); 77462306a36Sopenharmony_ci return 0; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci/* Add hmac identifires to the endpoint list of supported hmac ids */ 77862306a36Sopenharmony_ciint sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep, 77962306a36Sopenharmony_ci struct sctp_hmacalgo *hmacs) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci int has_sha1 = 0; 78262306a36Sopenharmony_ci __u16 id; 78362306a36Sopenharmony_ci int i; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* Scan the list looking for unsupported id. Also make sure that 78662306a36Sopenharmony_ci * SHA1 is specified. 78762306a36Sopenharmony_ci */ 78862306a36Sopenharmony_ci for (i = 0; i < hmacs->shmac_num_idents; i++) { 78962306a36Sopenharmony_ci id = hmacs->shmac_idents[i]; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (id > SCTP_AUTH_HMAC_ID_MAX) 79262306a36Sopenharmony_ci return -EOPNOTSUPP; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci if (SCTP_AUTH_HMAC_ID_SHA1 == id) 79562306a36Sopenharmony_ci has_sha1 = 1; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci if (!sctp_hmac_list[id].hmac_name) 79862306a36Sopenharmony_ci return -EOPNOTSUPP; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (!has_sha1) 80262306a36Sopenharmony_ci return -EINVAL; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci for (i = 0; i < hmacs->shmac_num_idents; i++) 80562306a36Sopenharmony_ci ep->auth_hmacs_list->hmac_ids[i] = 80662306a36Sopenharmony_ci htons(hmacs->shmac_idents[i]); 80762306a36Sopenharmony_ci ep->auth_hmacs_list->param_hdr.length = 80862306a36Sopenharmony_ci htons(sizeof(struct sctp_paramhdr) + 80962306a36Sopenharmony_ci hmacs->shmac_num_idents * sizeof(__u16)); 81062306a36Sopenharmony_ci return 0; 81162306a36Sopenharmony_ci} 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci/* Set a new shared key on either endpoint or association. If the 81462306a36Sopenharmony_ci * key with a same ID already exists, replace the key (remove the 81562306a36Sopenharmony_ci * old key and add a new one). 81662306a36Sopenharmony_ci */ 81762306a36Sopenharmony_ciint sctp_auth_set_key(struct sctp_endpoint *ep, 81862306a36Sopenharmony_ci struct sctp_association *asoc, 81962306a36Sopenharmony_ci struct sctp_authkey *auth_key) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci struct sctp_shared_key *cur_key, *shkey; 82262306a36Sopenharmony_ci struct sctp_auth_bytes *key; 82362306a36Sopenharmony_ci struct list_head *sh_keys; 82462306a36Sopenharmony_ci int replace = 0; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci /* Try to find the given key id to see if 82762306a36Sopenharmony_ci * we are doing a replace, or adding a new key 82862306a36Sopenharmony_ci */ 82962306a36Sopenharmony_ci if (asoc) { 83062306a36Sopenharmony_ci if (!asoc->peer.auth_capable) 83162306a36Sopenharmony_ci return -EACCES; 83262306a36Sopenharmony_ci sh_keys = &asoc->endpoint_shared_keys; 83362306a36Sopenharmony_ci } else { 83462306a36Sopenharmony_ci if (!ep->auth_enable) 83562306a36Sopenharmony_ci return -EACCES; 83662306a36Sopenharmony_ci sh_keys = &ep->endpoint_shared_keys; 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci key_for_each(shkey, sh_keys) { 84062306a36Sopenharmony_ci if (shkey->key_id == auth_key->sca_keynumber) { 84162306a36Sopenharmony_ci replace = 1; 84262306a36Sopenharmony_ci break; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci cur_key = sctp_auth_shkey_create(auth_key->sca_keynumber, GFP_KERNEL); 84762306a36Sopenharmony_ci if (!cur_key) 84862306a36Sopenharmony_ci return -ENOMEM; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci /* Create a new key data based on the info passed in */ 85162306a36Sopenharmony_ci key = sctp_auth_create_key(auth_key->sca_keylength, GFP_KERNEL); 85262306a36Sopenharmony_ci if (!key) { 85362306a36Sopenharmony_ci kfree(cur_key); 85462306a36Sopenharmony_ci return -ENOMEM; 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci memcpy(key->data, &auth_key->sca_key[0], auth_key->sca_keylength); 85862306a36Sopenharmony_ci cur_key->key = key; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci if (!replace) { 86162306a36Sopenharmony_ci list_add(&cur_key->key_list, sh_keys); 86262306a36Sopenharmony_ci return 0; 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci list_del_init(&shkey->key_list); 86662306a36Sopenharmony_ci list_add(&cur_key->key_list, sh_keys); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci if (asoc && asoc->active_key_id == auth_key->sca_keynumber && 86962306a36Sopenharmony_ci sctp_auth_asoc_init_active_key(asoc, GFP_KERNEL)) { 87062306a36Sopenharmony_ci list_del_init(&cur_key->key_list); 87162306a36Sopenharmony_ci sctp_auth_shkey_release(cur_key); 87262306a36Sopenharmony_ci list_add(&shkey->key_list, sh_keys); 87362306a36Sopenharmony_ci return -ENOMEM; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci sctp_auth_shkey_release(shkey); 87762306a36Sopenharmony_ci return 0; 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ciint sctp_auth_set_active_key(struct sctp_endpoint *ep, 88162306a36Sopenharmony_ci struct sctp_association *asoc, 88262306a36Sopenharmony_ci __u16 key_id) 88362306a36Sopenharmony_ci{ 88462306a36Sopenharmony_ci struct sctp_shared_key *key; 88562306a36Sopenharmony_ci struct list_head *sh_keys; 88662306a36Sopenharmony_ci int found = 0; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci /* The key identifier MUST correst to an existing key */ 88962306a36Sopenharmony_ci if (asoc) { 89062306a36Sopenharmony_ci if (!asoc->peer.auth_capable) 89162306a36Sopenharmony_ci return -EACCES; 89262306a36Sopenharmony_ci sh_keys = &asoc->endpoint_shared_keys; 89362306a36Sopenharmony_ci } else { 89462306a36Sopenharmony_ci if (!ep->auth_enable) 89562306a36Sopenharmony_ci return -EACCES; 89662306a36Sopenharmony_ci sh_keys = &ep->endpoint_shared_keys; 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci key_for_each(key, sh_keys) { 90062306a36Sopenharmony_ci if (key->key_id == key_id) { 90162306a36Sopenharmony_ci found = 1; 90262306a36Sopenharmony_ci break; 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci if (!found || key->deactivated) 90762306a36Sopenharmony_ci return -EINVAL; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci if (asoc) { 91062306a36Sopenharmony_ci __u16 active_key_id = asoc->active_key_id; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci asoc->active_key_id = key_id; 91362306a36Sopenharmony_ci if (sctp_auth_asoc_init_active_key(asoc, GFP_KERNEL)) { 91462306a36Sopenharmony_ci asoc->active_key_id = active_key_id; 91562306a36Sopenharmony_ci return -ENOMEM; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci } else 91862306a36Sopenharmony_ci ep->active_key_id = key_id; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci return 0; 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ciint sctp_auth_del_key_id(struct sctp_endpoint *ep, 92462306a36Sopenharmony_ci struct sctp_association *asoc, 92562306a36Sopenharmony_ci __u16 key_id) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci struct sctp_shared_key *key; 92862306a36Sopenharmony_ci struct list_head *sh_keys; 92962306a36Sopenharmony_ci int found = 0; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci /* The key identifier MUST NOT be the current active key 93262306a36Sopenharmony_ci * The key identifier MUST correst to an existing key 93362306a36Sopenharmony_ci */ 93462306a36Sopenharmony_ci if (asoc) { 93562306a36Sopenharmony_ci if (!asoc->peer.auth_capable) 93662306a36Sopenharmony_ci return -EACCES; 93762306a36Sopenharmony_ci if (asoc->active_key_id == key_id) 93862306a36Sopenharmony_ci return -EINVAL; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci sh_keys = &asoc->endpoint_shared_keys; 94162306a36Sopenharmony_ci } else { 94262306a36Sopenharmony_ci if (!ep->auth_enable) 94362306a36Sopenharmony_ci return -EACCES; 94462306a36Sopenharmony_ci if (ep->active_key_id == key_id) 94562306a36Sopenharmony_ci return -EINVAL; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci sh_keys = &ep->endpoint_shared_keys; 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci key_for_each(key, sh_keys) { 95162306a36Sopenharmony_ci if (key->key_id == key_id) { 95262306a36Sopenharmony_ci found = 1; 95362306a36Sopenharmony_ci break; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (!found) 95862306a36Sopenharmony_ci return -EINVAL; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci /* Delete the shared key */ 96162306a36Sopenharmony_ci list_del_init(&key->key_list); 96262306a36Sopenharmony_ci sctp_auth_shkey_release(key); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci return 0; 96562306a36Sopenharmony_ci} 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ciint sctp_auth_deact_key_id(struct sctp_endpoint *ep, 96862306a36Sopenharmony_ci struct sctp_association *asoc, __u16 key_id) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci struct sctp_shared_key *key; 97162306a36Sopenharmony_ci struct list_head *sh_keys; 97262306a36Sopenharmony_ci int found = 0; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci /* The key identifier MUST NOT be the current active key 97562306a36Sopenharmony_ci * The key identifier MUST correst to an existing key 97662306a36Sopenharmony_ci */ 97762306a36Sopenharmony_ci if (asoc) { 97862306a36Sopenharmony_ci if (!asoc->peer.auth_capable) 97962306a36Sopenharmony_ci return -EACCES; 98062306a36Sopenharmony_ci if (asoc->active_key_id == key_id) 98162306a36Sopenharmony_ci return -EINVAL; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci sh_keys = &asoc->endpoint_shared_keys; 98462306a36Sopenharmony_ci } else { 98562306a36Sopenharmony_ci if (!ep->auth_enable) 98662306a36Sopenharmony_ci return -EACCES; 98762306a36Sopenharmony_ci if (ep->active_key_id == key_id) 98862306a36Sopenharmony_ci return -EINVAL; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci sh_keys = &ep->endpoint_shared_keys; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci key_for_each(key, sh_keys) { 99462306a36Sopenharmony_ci if (key->key_id == key_id) { 99562306a36Sopenharmony_ci found = 1; 99662306a36Sopenharmony_ci break; 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci if (!found) 100162306a36Sopenharmony_ci return -EINVAL; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci /* refcnt == 1 and !list_empty mean it's not being used anywhere 100462306a36Sopenharmony_ci * and deactivated will be set, so it's time to notify userland 100562306a36Sopenharmony_ci * that this shkey can be freed. 100662306a36Sopenharmony_ci */ 100762306a36Sopenharmony_ci if (asoc && !list_empty(&key->key_list) && 100862306a36Sopenharmony_ci refcount_read(&key->refcnt) == 1) { 100962306a36Sopenharmony_ci struct sctp_ulpevent *ev; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci ev = sctp_ulpevent_make_authkey(asoc, key->key_id, 101262306a36Sopenharmony_ci SCTP_AUTH_FREE_KEY, GFP_KERNEL); 101362306a36Sopenharmony_ci if (ev) 101462306a36Sopenharmony_ci asoc->stream.si->enqueue_event(&asoc->ulpq, ev); 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci key->deactivated = 1; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci return 0; 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ciint sctp_auth_init(struct sctp_endpoint *ep, gfp_t gfp) 102362306a36Sopenharmony_ci{ 102462306a36Sopenharmony_ci int err = -ENOMEM; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci /* Allocate space for HMACS and CHUNKS authentication 102762306a36Sopenharmony_ci * variables. There are arrays that we encode directly 102862306a36Sopenharmony_ci * into parameters to make the rest of the operations easier. 102962306a36Sopenharmony_ci */ 103062306a36Sopenharmony_ci if (!ep->auth_hmacs_list) { 103162306a36Sopenharmony_ci struct sctp_hmac_algo_param *auth_hmacs; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci auth_hmacs = kzalloc(struct_size(auth_hmacs, hmac_ids, 103462306a36Sopenharmony_ci SCTP_AUTH_NUM_HMACS), gfp); 103562306a36Sopenharmony_ci if (!auth_hmacs) 103662306a36Sopenharmony_ci goto nomem; 103762306a36Sopenharmony_ci /* Initialize the HMACS parameter. 103862306a36Sopenharmony_ci * SCTP-AUTH: Section 3.3 103962306a36Sopenharmony_ci * Every endpoint supporting SCTP chunk authentication MUST 104062306a36Sopenharmony_ci * support the HMAC based on the SHA-1 algorithm. 104162306a36Sopenharmony_ci */ 104262306a36Sopenharmony_ci auth_hmacs->param_hdr.type = SCTP_PARAM_HMAC_ALGO; 104362306a36Sopenharmony_ci auth_hmacs->param_hdr.length = 104462306a36Sopenharmony_ci htons(sizeof(struct sctp_paramhdr) + 2); 104562306a36Sopenharmony_ci auth_hmacs->hmac_ids[0] = htons(SCTP_AUTH_HMAC_ID_SHA1); 104662306a36Sopenharmony_ci ep->auth_hmacs_list = auth_hmacs; 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci if (!ep->auth_chunk_list) { 105062306a36Sopenharmony_ci struct sctp_chunks_param *auth_chunks; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci auth_chunks = kzalloc(sizeof(*auth_chunks) + 105362306a36Sopenharmony_ci SCTP_NUM_CHUNK_TYPES, gfp); 105462306a36Sopenharmony_ci if (!auth_chunks) 105562306a36Sopenharmony_ci goto nomem; 105662306a36Sopenharmony_ci /* Initialize the CHUNKS parameter */ 105762306a36Sopenharmony_ci auth_chunks->param_hdr.type = SCTP_PARAM_CHUNKS; 105862306a36Sopenharmony_ci auth_chunks->param_hdr.length = 105962306a36Sopenharmony_ci htons(sizeof(struct sctp_paramhdr)); 106062306a36Sopenharmony_ci ep->auth_chunk_list = auth_chunks; 106162306a36Sopenharmony_ci } 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* Allocate and initialize transorms arrays for supported 106462306a36Sopenharmony_ci * HMACs. 106562306a36Sopenharmony_ci */ 106662306a36Sopenharmony_ci err = sctp_auth_init_hmacs(ep, gfp); 106762306a36Sopenharmony_ci if (err) 106862306a36Sopenharmony_ci goto nomem; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci return 0; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_cinomem: 107362306a36Sopenharmony_ci /* Free all allocations */ 107462306a36Sopenharmony_ci kfree(ep->auth_hmacs_list); 107562306a36Sopenharmony_ci kfree(ep->auth_chunk_list); 107662306a36Sopenharmony_ci ep->auth_hmacs_list = NULL; 107762306a36Sopenharmony_ci ep->auth_chunk_list = NULL; 107862306a36Sopenharmony_ci return err; 107962306a36Sopenharmony_ci} 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_civoid sctp_auth_free(struct sctp_endpoint *ep) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci kfree(ep->auth_hmacs_list); 108462306a36Sopenharmony_ci kfree(ep->auth_chunk_list); 108562306a36Sopenharmony_ci ep->auth_hmacs_list = NULL; 108662306a36Sopenharmony_ci ep->auth_chunk_list = NULL; 108762306a36Sopenharmony_ci sctp_auth_destroy_hmacs(ep->auth_hmacs); 108862306a36Sopenharmony_ci ep->auth_hmacs = NULL; 108962306a36Sopenharmony_ci} 1090