18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* SCTP kernel implementation 38c2ecf20Sopenharmony_ci * (C) Copyright 2007 Hewlett-Packard Development Company, L.P. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file is part of the SCTP kernel implementation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Please send any bug reports or fixes you make to the 88c2ecf20Sopenharmony_ci * email address(es): 98c2ecf20Sopenharmony_ci * lksctp developers <linux-sctp@vger.kernel.org> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Written or modified by: 128c2ecf20Sopenharmony_ci * Vlad Yasevich <vladislav.yasevich@hp.com> 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <crypto/hash.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/types.h> 188c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 198c2ecf20Sopenharmony_ci#include <net/sctp/sctp.h> 208c2ecf20Sopenharmony_ci#include <net/sctp/auth.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic struct sctp_hmac sctp_hmac_list[SCTP_AUTH_NUM_HMACS] = { 238c2ecf20Sopenharmony_ci { 248c2ecf20Sopenharmony_ci /* id 0 is reserved. as all 0 */ 258c2ecf20Sopenharmony_ci .hmac_id = SCTP_AUTH_HMAC_ID_RESERVED_0, 268c2ecf20Sopenharmony_ci }, 278c2ecf20Sopenharmony_ci { 288c2ecf20Sopenharmony_ci .hmac_id = SCTP_AUTH_HMAC_ID_SHA1, 298c2ecf20Sopenharmony_ci .hmac_name = "hmac(sha1)", 308c2ecf20Sopenharmony_ci .hmac_len = SCTP_SHA1_SIG_SIZE, 318c2ecf20Sopenharmony_ci }, 328c2ecf20Sopenharmony_ci { 338c2ecf20Sopenharmony_ci /* id 2 is reserved as well */ 348c2ecf20Sopenharmony_ci .hmac_id = SCTP_AUTH_HMAC_ID_RESERVED_2, 358c2ecf20Sopenharmony_ci }, 368c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_CRYPTO_SHA256) 378c2ecf20Sopenharmony_ci { 388c2ecf20Sopenharmony_ci .hmac_id = SCTP_AUTH_HMAC_ID_SHA256, 398c2ecf20Sopenharmony_ci .hmac_name = "hmac(sha256)", 408c2ecf20Sopenharmony_ci .hmac_len = SCTP_SHA256_SIG_SIZE, 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci#endif 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_civoid sctp_auth_key_put(struct sctp_auth_bytes *key) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci if (!key) 498c2ecf20Sopenharmony_ci return; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&key->refcnt)) { 528c2ecf20Sopenharmony_ci kfree_sensitive(key); 538c2ecf20Sopenharmony_ci SCTP_DBG_OBJCNT_DEC(keys); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* Create a new key structure of a given length */ 588c2ecf20Sopenharmony_cistatic struct sctp_auth_bytes *sctp_auth_create_key(__u32 key_len, gfp_t gfp) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci struct sctp_auth_bytes *key; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* Verify that we are not going to overflow INT_MAX */ 638c2ecf20Sopenharmony_ci if (key_len > (INT_MAX - sizeof(struct sctp_auth_bytes))) 648c2ecf20Sopenharmony_ci return NULL; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* Allocate the shared key */ 678c2ecf20Sopenharmony_ci key = kmalloc(sizeof(struct sctp_auth_bytes) + key_len, gfp); 688c2ecf20Sopenharmony_ci if (!key) 698c2ecf20Sopenharmony_ci return NULL; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci key->len = key_len; 728c2ecf20Sopenharmony_ci refcount_set(&key->refcnt, 1); 738c2ecf20Sopenharmony_ci SCTP_DBG_OBJCNT_INC(keys); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return key; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* Create a new shared key container with a give key id */ 798c2ecf20Sopenharmony_cistruct sctp_shared_key *sctp_auth_shkey_create(__u16 key_id, gfp_t gfp) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct sctp_shared_key *new; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* Allocate the shared key container */ 848c2ecf20Sopenharmony_ci new = kzalloc(sizeof(struct sctp_shared_key), gfp); 858c2ecf20Sopenharmony_ci if (!new) 868c2ecf20Sopenharmony_ci return NULL; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&new->key_list); 898c2ecf20Sopenharmony_ci refcount_set(&new->refcnt, 1); 908c2ecf20Sopenharmony_ci new->key_id = key_id; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci return new; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/* Free the shared key structure */ 968c2ecf20Sopenharmony_cistatic void sctp_auth_shkey_destroy(struct sctp_shared_key *sh_key) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci BUG_ON(!list_empty(&sh_key->key_list)); 998c2ecf20Sopenharmony_ci sctp_auth_key_put(sh_key->key); 1008c2ecf20Sopenharmony_ci sh_key->key = NULL; 1018c2ecf20Sopenharmony_ci kfree(sh_key); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_civoid sctp_auth_shkey_release(struct sctp_shared_key *sh_key) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&sh_key->refcnt)) 1078c2ecf20Sopenharmony_ci sctp_auth_shkey_destroy(sh_key); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_civoid sctp_auth_shkey_hold(struct sctp_shared_key *sh_key) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci refcount_inc(&sh_key->refcnt); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* Destroy the entire key list. This is done during the 1168c2ecf20Sopenharmony_ci * associon and endpoint free process. 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_civoid sctp_auth_destroy_keys(struct list_head *keys) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci struct sctp_shared_key *ep_key; 1218c2ecf20Sopenharmony_ci struct sctp_shared_key *tmp; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (list_empty(keys)) 1248c2ecf20Sopenharmony_ci return; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci key_for_each_safe(ep_key, tmp, keys) { 1278c2ecf20Sopenharmony_ci list_del_init(&ep_key->key_list); 1288c2ecf20Sopenharmony_ci sctp_auth_shkey_release(ep_key); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* Compare two byte vectors as numbers. Return values 1338c2ecf20Sopenharmony_ci * are: 1348c2ecf20Sopenharmony_ci * 0 - vectors are equal 1358c2ecf20Sopenharmony_ci * < 0 - vector 1 is smaller than vector2 1368c2ecf20Sopenharmony_ci * > 0 - vector 1 is greater than vector2 1378c2ecf20Sopenharmony_ci * 1388c2ecf20Sopenharmony_ci * Algorithm is: 1398c2ecf20Sopenharmony_ci * This is performed by selecting the numerically smaller key vector... 1408c2ecf20Sopenharmony_ci * If the key vectors are equal as numbers but differ in length ... 1418c2ecf20Sopenharmony_ci * the shorter vector is considered smaller 1428c2ecf20Sopenharmony_ci * 1438c2ecf20Sopenharmony_ci * Examples (with small values): 1448c2ecf20Sopenharmony_ci * 000123456789 > 123456789 (first number is longer) 1458c2ecf20Sopenharmony_ci * 000123456789 < 234567891 (second number is larger numerically) 1468c2ecf20Sopenharmony_ci * 123456789 > 2345678 (first number is both larger & longer) 1478c2ecf20Sopenharmony_ci */ 1488c2ecf20Sopenharmony_cistatic int sctp_auth_compare_vectors(struct sctp_auth_bytes *vector1, 1498c2ecf20Sopenharmony_ci struct sctp_auth_bytes *vector2) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci int diff; 1528c2ecf20Sopenharmony_ci int i; 1538c2ecf20Sopenharmony_ci const __u8 *longer; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci diff = vector1->len - vector2->len; 1568c2ecf20Sopenharmony_ci if (diff) { 1578c2ecf20Sopenharmony_ci longer = (diff > 0) ? vector1->data : vector2->data; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* Check to see if the longer number is 1608c2ecf20Sopenharmony_ci * lead-zero padded. If it is not, it 1618c2ecf20Sopenharmony_ci * is automatically larger numerically. 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_ci for (i = 0; i < abs(diff); i++) { 1648c2ecf20Sopenharmony_ci if (longer[i] != 0) 1658c2ecf20Sopenharmony_ci return diff; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* lengths are the same, compare numbers */ 1708c2ecf20Sopenharmony_ci return memcmp(vector1->data, vector2->data, vector1->len); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/* 1748c2ecf20Sopenharmony_ci * Create a key vector as described in SCTP-AUTH, Section 6.1 1758c2ecf20Sopenharmony_ci * The RANDOM parameter, the CHUNKS parameter and the HMAC-ALGO 1768c2ecf20Sopenharmony_ci * parameter sent by each endpoint are concatenated as byte vectors. 1778c2ecf20Sopenharmony_ci * These parameters include the parameter type, parameter length, and 1788c2ecf20Sopenharmony_ci * the parameter value, but padding is omitted; all padding MUST be 1798c2ecf20Sopenharmony_ci * removed from this concatenation before proceeding with further 1808c2ecf20Sopenharmony_ci * computation of keys. Parameters which were not sent are simply 1818c2ecf20Sopenharmony_ci * omitted from the concatenation process. The resulting two vectors 1828c2ecf20Sopenharmony_ci * are called the two key vectors. 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_cistatic struct sctp_auth_bytes *sctp_auth_make_key_vector( 1858c2ecf20Sopenharmony_ci struct sctp_random_param *random, 1868c2ecf20Sopenharmony_ci struct sctp_chunks_param *chunks, 1878c2ecf20Sopenharmony_ci struct sctp_hmac_algo_param *hmacs, 1888c2ecf20Sopenharmony_ci gfp_t gfp) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct sctp_auth_bytes *new; 1918c2ecf20Sopenharmony_ci __u32 len; 1928c2ecf20Sopenharmony_ci __u32 offset = 0; 1938c2ecf20Sopenharmony_ci __u16 random_len, hmacs_len, chunks_len = 0; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci random_len = ntohs(random->param_hdr.length); 1968c2ecf20Sopenharmony_ci hmacs_len = ntohs(hmacs->param_hdr.length); 1978c2ecf20Sopenharmony_ci if (chunks) 1988c2ecf20Sopenharmony_ci chunks_len = ntohs(chunks->param_hdr.length); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci len = random_len + hmacs_len + chunks_len; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci new = sctp_auth_create_key(len, gfp); 2038c2ecf20Sopenharmony_ci if (!new) 2048c2ecf20Sopenharmony_ci return NULL; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci memcpy(new->data, random, random_len); 2078c2ecf20Sopenharmony_ci offset += random_len; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (chunks) { 2108c2ecf20Sopenharmony_ci memcpy(new->data + offset, chunks, chunks_len); 2118c2ecf20Sopenharmony_ci offset += chunks_len; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci memcpy(new->data + offset, hmacs, hmacs_len); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci return new; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/* Make a key vector based on our local parameters */ 2218c2ecf20Sopenharmony_cistatic struct sctp_auth_bytes *sctp_auth_make_local_vector( 2228c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 2238c2ecf20Sopenharmony_ci gfp_t gfp) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci return sctp_auth_make_key_vector( 2268c2ecf20Sopenharmony_ci (struct sctp_random_param *)asoc->c.auth_random, 2278c2ecf20Sopenharmony_ci (struct sctp_chunks_param *)asoc->c.auth_chunks, 2288c2ecf20Sopenharmony_ci (struct sctp_hmac_algo_param *)asoc->c.auth_hmacs, gfp); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/* Make a key vector based on peer's parameters */ 2328c2ecf20Sopenharmony_cistatic struct sctp_auth_bytes *sctp_auth_make_peer_vector( 2338c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 2348c2ecf20Sopenharmony_ci gfp_t gfp) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci return sctp_auth_make_key_vector(asoc->peer.peer_random, 2378c2ecf20Sopenharmony_ci asoc->peer.peer_chunks, 2388c2ecf20Sopenharmony_ci asoc->peer.peer_hmacs, 2398c2ecf20Sopenharmony_ci gfp); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci/* Set the value of the association shared key base on the parameters 2448c2ecf20Sopenharmony_ci * given. The algorithm is: 2458c2ecf20Sopenharmony_ci * From the endpoint pair shared keys and the key vectors the 2468c2ecf20Sopenharmony_ci * association shared keys are computed. This is performed by selecting 2478c2ecf20Sopenharmony_ci * the numerically smaller key vector and concatenating it to the 2488c2ecf20Sopenharmony_ci * endpoint pair shared key, and then concatenating the numerically 2498c2ecf20Sopenharmony_ci * larger key vector to that. The result of the concatenation is the 2508c2ecf20Sopenharmony_ci * association shared key. 2518c2ecf20Sopenharmony_ci */ 2528c2ecf20Sopenharmony_cistatic struct sctp_auth_bytes *sctp_auth_asoc_set_secret( 2538c2ecf20Sopenharmony_ci struct sctp_shared_key *ep_key, 2548c2ecf20Sopenharmony_ci struct sctp_auth_bytes *first_vector, 2558c2ecf20Sopenharmony_ci struct sctp_auth_bytes *last_vector, 2568c2ecf20Sopenharmony_ci gfp_t gfp) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci struct sctp_auth_bytes *secret; 2598c2ecf20Sopenharmony_ci __u32 offset = 0; 2608c2ecf20Sopenharmony_ci __u32 auth_len; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci auth_len = first_vector->len + last_vector->len; 2638c2ecf20Sopenharmony_ci if (ep_key->key) 2648c2ecf20Sopenharmony_ci auth_len += ep_key->key->len; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci secret = sctp_auth_create_key(auth_len, gfp); 2678c2ecf20Sopenharmony_ci if (!secret) 2688c2ecf20Sopenharmony_ci return NULL; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (ep_key->key) { 2718c2ecf20Sopenharmony_ci memcpy(secret->data, ep_key->key->data, ep_key->key->len); 2728c2ecf20Sopenharmony_ci offset += ep_key->key->len; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci memcpy(secret->data + offset, first_vector->data, first_vector->len); 2768c2ecf20Sopenharmony_ci offset += first_vector->len; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci memcpy(secret->data + offset, last_vector->data, last_vector->len); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci return secret; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci/* Create an association shared key. Follow the algorithm 2848c2ecf20Sopenharmony_ci * described in SCTP-AUTH, Section 6.1 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_cistatic struct sctp_auth_bytes *sctp_auth_asoc_create_secret( 2878c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 2888c2ecf20Sopenharmony_ci struct sctp_shared_key *ep_key, 2898c2ecf20Sopenharmony_ci gfp_t gfp) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct sctp_auth_bytes *local_key_vector; 2928c2ecf20Sopenharmony_ci struct sctp_auth_bytes *peer_key_vector; 2938c2ecf20Sopenharmony_ci struct sctp_auth_bytes *first_vector, 2948c2ecf20Sopenharmony_ci *last_vector; 2958c2ecf20Sopenharmony_ci struct sctp_auth_bytes *secret = NULL; 2968c2ecf20Sopenharmony_ci int cmp; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* Now we need to build the key vectors 3008c2ecf20Sopenharmony_ci * SCTP-AUTH , Section 6.1 3018c2ecf20Sopenharmony_ci * The RANDOM parameter, the CHUNKS parameter and the HMAC-ALGO 3028c2ecf20Sopenharmony_ci * parameter sent by each endpoint are concatenated as byte vectors. 3038c2ecf20Sopenharmony_ci * These parameters include the parameter type, parameter length, and 3048c2ecf20Sopenharmony_ci * the parameter value, but padding is omitted; all padding MUST be 3058c2ecf20Sopenharmony_ci * removed from this concatenation before proceeding with further 3068c2ecf20Sopenharmony_ci * computation of keys. Parameters which were not sent are simply 3078c2ecf20Sopenharmony_ci * omitted from the concatenation process. The resulting two vectors 3088c2ecf20Sopenharmony_ci * are called the two key vectors. 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci local_key_vector = sctp_auth_make_local_vector(asoc, gfp); 3128c2ecf20Sopenharmony_ci peer_key_vector = sctp_auth_make_peer_vector(asoc, gfp); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (!peer_key_vector || !local_key_vector) 3158c2ecf20Sopenharmony_ci goto out; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* Figure out the order in which the key_vectors will be 3188c2ecf20Sopenharmony_ci * added to the endpoint shared key. 3198c2ecf20Sopenharmony_ci * SCTP-AUTH, Section 6.1: 3208c2ecf20Sopenharmony_ci * This is performed by selecting the numerically smaller key 3218c2ecf20Sopenharmony_ci * vector and concatenating it to the endpoint pair shared 3228c2ecf20Sopenharmony_ci * key, and then concatenating the numerically larger key 3238c2ecf20Sopenharmony_ci * vector to that. If the key vectors are equal as numbers 3248c2ecf20Sopenharmony_ci * but differ in length, then the concatenation order is the 3258c2ecf20Sopenharmony_ci * endpoint shared key, followed by the shorter key vector, 3268c2ecf20Sopenharmony_ci * followed by the longer key vector. Otherwise, the key 3278c2ecf20Sopenharmony_ci * vectors are identical, and may be concatenated to the 3288c2ecf20Sopenharmony_ci * endpoint pair key in any order. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_ci cmp = sctp_auth_compare_vectors(local_key_vector, 3318c2ecf20Sopenharmony_ci peer_key_vector); 3328c2ecf20Sopenharmony_ci if (cmp < 0) { 3338c2ecf20Sopenharmony_ci first_vector = local_key_vector; 3348c2ecf20Sopenharmony_ci last_vector = peer_key_vector; 3358c2ecf20Sopenharmony_ci } else { 3368c2ecf20Sopenharmony_ci first_vector = peer_key_vector; 3378c2ecf20Sopenharmony_ci last_vector = local_key_vector; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci secret = sctp_auth_asoc_set_secret(ep_key, first_vector, last_vector, 3418c2ecf20Sopenharmony_ci gfp); 3428c2ecf20Sopenharmony_ciout: 3438c2ecf20Sopenharmony_ci sctp_auth_key_put(local_key_vector); 3448c2ecf20Sopenharmony_ci sctp_auth_key_put(peer_key_vector); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return secret; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/* 3508c2ecf20Sopenharmony_ci * Populate the association overlay list with the list 3518c2ecf20Sopenharmony_ci * from the endpoint. 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_ciint sctp_auth_asoc_copy_shkeys(const struct sctp_endpoint *ep, 3548c2ecf20Sopenharmony_ci struct sctp_association *asoc, 3558c2ecf20Sopenharmony_ci gfp_t gfp) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct sctp_shared_key *sh_key; 3588c2ecf20Sopenharmony_ci struct sctp_shared_key *new; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci BUG_ON(!list_empty(&asoc->endpoint_shared_keys)); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci key_for_each(sh_key, &ep->endpoint_shared_keys) { 3638c2ecf20Sopenharmony_ci new = sctp_auth_shkey_create(sh_key->key_id, gfp); 3648c2ecf20Sopenharmony_ci if (!new) 3658c2ecf20Sopenharmony_ci goto nomem; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci new->key = sh_key->key; 3688c2ecf20Sopenharmony_ci sctp_auth_key_hold(new->key); 3698c2ecf20Sopenharmony_ci list_add(&new->key_list, &asoc->endpoint_shared_keys); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return 0; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cinomem: 3758c2ecf20Sopenharmony_ci sctp_auth_destroy_keys(&asoc->endpoint_shared_keys); 3768c2ecf20Sopenharmony_ci return -ENOMEM; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci/* Public interface to create the association shared key. 3818c2ecf20Sopenharmony_ci * See code above for the algorithm. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ciint sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct sctp_auth_bytes *secret; 3868c2ecf20Sopenharmony_ci struct sctp_shared_key *ep_key; 3878c2ecf20Sopenharmony_ci struct sctp_chunk *chunk; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* If we don't support AUTH, or peer is not capable 3908c2ecf20Sopenharmony_ci * we don't need to do anything. 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_ci if (!asoc->peer.auth_capable) 3938c2ecf20Sopenharmony_ci return 0; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* If the key_id is non-zero and we couldn't find an 3968c2ecf20Sopenharmony_ci * endpoint pair shared key, we can't compute the 3978c2ecf20Sopenharmony_ci * secret. 3988c2ecf20Sopenharmony_ci * For key_id 0, endpoint pair shared key is a NULL key. 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_ci ep_key = sctp_auth_get_shkey(asoc, asoc->active_key_id); 4018c2ecf20Sopenharmony_ci BUG_ON(!ep_key); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci secret = sctp_auth_asoc_create_secret(asoc, ep_key, gfp); 4048c2ecf20Sopenharmony_ci if (!secret) 4058c2ecf20Sopenharmony_ci return -ENOMEM; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci sctp_auth_key_put(asoc->asoc_shared_key); 4088c2ecf20Sopenharmony_ci asoc->asoc_shared_key = secret; 4098c2ecf20Sopenharmony_ci asoc->shkey = ep_key; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* Update send queue in case any chunk already in there now 4128c2ecf20Sopenharmony_ci * needs authenticating 4138c2ecf20Sopenharmony_ci */ 4148c2ecf20Sopenharmony_ci list_for_each_entry(chunk, &asoc->outqueue.out_chunk_list, list) { 4158c2ecf20Sopenharmony_ci if (sctp_auth_send_cid(chunk->chunk_hdr->type, asoc)) { 4168c2ecf20Sopenharmony_ci chunk->auth = 1; 4178c2ecf20Sopenharmony_ci if (!chunk->shkey) { 4188c2ecf20Sopenharmony_ci chunk->shkey = asoc->shkey; 4198c2ecf20Sopenharmony_ci sctp_auth_shkey_hold(chunk->shkey); 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return 0; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci/* Find the endpoint pair shared key based on the key_id */ 4298c2ecf20Sopenharmony_cistruct sctp_shared_key *sctp_auth_get_shkey( 4308c2ecf20Sopenharmony_ci const struct sctp_association *asoc, 4318c2ecf20Sopenharmony_ci __u16 key_id) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct sctp_shared_key *key; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* First search associations set of endpoint pair shared keys */ 4368c2ecf20Sopenharmony_ci key_for_each(key, &asoc->endpoint_shared_keys) { 4378c2ecf20Sopenharmony_ci if (key->key_id == key_id) { 4388c2ecf20Sopenharmony_ci if (!key->deactivated) 4398c2ecf20Sopenharmony_ci return key; 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return NULL; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci/* 4488c2ecf20Sopenharmony_ci * Initialize all the possible digest transforms that we can use. Right 4498c2ecf20Sopenharmony_ci * now, the supported digests are SHA1 and SHA256. We do this here once 4508c2ecf20Sopenharmony_ci * because of the restrictiong that transforms may only be allocated in 4518c2ecf20Sopenharmony_ci * user context. This forces us to pre-allocated all possible transforms 4528c2ecf20Sopenharmony_ci * at the endpoint init time. 4538c2ecf20Sopenharmony_ci */ 4548c2ecf20Sopenharmony_ciint sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct crypto_shash *tfm = NULL; 4578c2ecf20Sopenharmony_ci __u16 id; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci /* If the transforms are already allocated, we are done */ 4608c2ecf20Sopenharmony_ci if (ep->auth_hmacs) 4618c2ecf20Sopenharmony_ci return 0; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* Allocated the array of pointers to transorms */ 4648c2ecf20Sopenharmony_ci ep->auth_hmacs = kcalloc(SCTP_AUTH_NUM_HMACS, 4658c2ecf20Sopenharmony_ci sizeof(struct crypto_shash *), 4668c2ecf20Sopenharmony_ci gfp); 4678c2ecf20Sopenharmony_ci if (!ep->auth_hmacs) 4688c2ecf20Sopenharmony_ci return -ENOMEM; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci for (id = 0; id < SCTP_AUTH_NUM_HMACS; id++) { 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* See is we support the id. Supported IDs have name and 4738c2ecf20Sopenharmony_ci * length fields set, so that we can allocated and use 4748c2ecf20Sopenharmony_ci * them. We can safely just check for name, for without the 4758c2ecf20Sopenharmony_ci * name, we can't allocate the TFM. 4768c2ecf20Sopenharmony_ci */ 4778c2ecf20Sopenharmony_ci if (!sctp_hmac_list[id].hmac_name) 4788c2ecf20Sopenharmony_ci continue; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* If this TFM has been allocated, we are all set */ 4818c2ecf20Sopenharmony_ci if (ep->auth_hmacs[id]) 4828c2ecf20Sopenharmony_ci continue; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* Allocate the ID */ 4858c2ecf20Sopenharmony_ci tfm = crypto_alloc_shash(sctp_hmac_list[id].hmac_name, 0, 0); 4868c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) 4878c2ecf20Sopenharmony_ci goto out_err; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci ep->auth_hmacs[id] = tfm; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci return 0; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ciout_err: 4958c2ecf20Sopenharmony_ci /* Clean up any successful allocations */ 4968c2ecf20Sopenharmony_ci sctp_auth_destroy_hmacs(ep->auth_hmacs); 4978c2ecf20Sopenharmony_ci ep->auth_hmacs = NULL; 4988c2ecf20Sopenharmony_ci return -ENOMEM; 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci/* Destroy the hmac tfm array */ 5028c2ecf20Sopenharmony_civoid sctp_auth_destroy_hmacs(struct crypto_shash *auth_hmacs[]) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci int i; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (!auth_hmacs) 5078c2ecf20Sopenharmony_ci return; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci for (i = 0; i < SCTP_AUTH_NUM_HMACS; i++) { 5108c2ecf20Sopenharmony_ci crypto_free_shash(auth_hmacs[i]); 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci kfree(auth_hmacs); 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistruct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci return &sctp_hmac_list[hmac_id]; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci/* Get an hmac description information that we can use to build 5228c2ecf20Sopenharmony_ci * the AUTH chunk 5238c2ecf20Sopenharmony_ci */ 5248c2ecf20Sopenharmony_cistruct sctp_hmac *sctp_auth_asoc_get_hmac(const struct sctp_association *asoc) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci struct sctp_hmac_algo_param *hmacs; 5278c2ecf20Sopenharmony_ci __u16 n_elt; 5288c2ecf20Sopenharmony_ci __u16 id = 0; 5298c2ecf20Sopenharmony_ci int i; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* If we have a default entry, use it */ 5328c2ecf20Sopenharmony_ci if (asoc->default_hmac_id) 5338c2ecf20Sopenharmony_ci return &sctp_hmac_list[asoc->default_hmac_id]; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci /* Since we do not have a default entry, find the first entry 5368c2ecf20Sopenharmony_ci * we support and return that. Do not cache that id. 5378c2ecf20Sopenharmony_ci */ 5388c2ecf20Sopenharmony_ci hmacs = asoc->peer.peer_hmacs; 5398c2ecf20Sopenharmony_ci if (!hmacs) 5408c2ecf20Sopenharmony_ci return NULL; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci n_elt = (ntohs(hmacs->param_hdr.length) - 5438c2ecf20Sopenharmony_ci sizeof(struct sctp_paramhdr)) >> 1; 5448c2ecf20Sopenharmony_ci for (i = 0; i < n_elt; i++) { 5458c2ecf20Sopenharmony_ci id = ntohs(hmacs->hmac_ids[i]); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* Check the id is in the supported range. And 5488c2ecf20Sopenharmony_ci * see if we support the id. Supported IDs have name and 5498c2ecf20Sopenharmony_ci * length fields set, so that we can allocate and use 5508c2ecf20Sopenharmony_ci * them. We can safely just check for name, for without the 5518c2ecf20Sopenharmony_ci * name, we can't allocate the TFM. 5528c2ecf20Sopenharmony_ci */ 5538c2ecf20Sopenharmony_ci if (id > SCTP_AUTH_HMAC_ID_MAX || 5548c2ecf20Sopenharmony_ci !sctp_hmac_list[id].hmac_name) { 5558c2ecf20Sopenharmony_ci id = 0; 5568c2ecf20Sopenharmony_ci continue; 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci break; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (id == 0) 5638c2ecf20Sopenharmony_ci return NULL; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci return &sctp_hmac_list[id]; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic int __sctp_auth_find_hmacid(__be16 *hmacs, int n_elts, __be16 hmac_id) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci int found = 0; 5718c2ecf20Sopenharmony_ci int i; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci for (i = 0; i < n_elts; i++) { 5748c2ecf20Sopenharmony_ci if (hmac_id == hmacs[i]) { 5758c2ecf20Sopenharmony_ci found = 1; 5768c2ecf20Sopenharmony_ci break; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci return found; 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci/* See if the HMAC_ID is one that we claim as supported */ 5848c2ecf20Sopenharmony_ciint sctp_auth_asoc_verify_hmac_id(const struct sctp_association *asoc, 5858c2ecf20Sopenharmony_ci __be16 hmac_id) 5868c2ecf20Sopenharmony_ci{ 5878c2ecf20Sopenharmony_ci struct sctp_hmac_algo_param *hmacs; 5888c2ecf20Sopenharmony_ci __u16 n_elt; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (!asoc) 5918c2ecf20Sopenharmony_ci return 0; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci hmacs = (struct sctp_hmac_algo_param *)asoc->c.auth_hmacs; 5948c2ecf20Sopenharmony_ci n_elt = (ntohs(hmacs->param_hdr.length) - 5958c2ecf20Sopenharmony_ci sizeof(struct sctp_paramhdr)) >> 1; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci return __sctp_auth_find_hmacid(hmacs->hmac_ids, n_elt, hmac_id); 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci/* Cache the default HMAC id. This to follow this text from SCTP-AUTH: 6028c2ecf20Sopenharmony_ci * Section 6.1: 6038c2ecf20Sopenharmony_ci * The receiver of a HMAC-ALGO parameter SHOULD use the first listed 6048c2ecf20Sopenharmony_ci * algorithm it supports. 6058c2ecf20Sopenharmony_ci */ 6068c2ecf20Sopenharmony_civoid sctp_auth_asoc_set_default_hmac(struct sctp_association *asoc, 6078c2ecf20Sopenharmony_ci struct sctp_hmac_algo_param *hmacs) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci struct sctp_endpoint *ep; 6108c2ecf20Sopenharmony_ci __u16 id; 6118c2ecf20Sopenharmony_ci int i; 6128c2ecf20Sopenharmony_ci int n_params; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* if the default id is already set, use it */ 6158c2ecf20Sopenharmony_ci if (asoc->default_hmac_id) 6168c2ecf20Sopenharmony_ci return; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci n_params = (ntohs(hmacs->param_hdr.length) - 6198c2ecf20Sopenharmony_ci sizeof(struct sctp_paramhdr)) >> 1; 6208c2ecf20Sopenharmony_ci ep = asoc->ep; 6218c2ecf20Sopenharmony_ci for (i = 0; i < n_params; i++) { 6228c2ecf20Sopenharmony_ci id = ntohs(hmacs->hmac_ids[i]); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* Check the id is in the supported range */ 6258c2ecf20Sopenharmony_ci if (id > SCTP_AUTH_HMAC_ID_MAX) 6268c2ecf20Sopenharmony_ci continue; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* If this TFM has been allocated, use this id */ 6298c2ecf20Sopenharmony_ci if (ep->auth_hmacs[id]) { 6308c2ecf20Sopenharmony_ci asoc->default_hmac_id = id; 6318c2ecf20Sopenharmony_ci break; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci/* Check to see if the given chunk is supposed to be authenticated */ 6388c2ecf20Sopenharmony_cistatic int __sctp_auth_cid(enum sctp_cid chunk, struct sctp_chunks_param *param) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci unsigned short len; 6418c2ecf20Sopenharmony_ci int found = 0; 6428c2ecf20Sopenharmony_ci int i; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (!param || param->param_hdr.length == 0) 6458c2ecf20Sopenharmony_ci return 0; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci len = ntohs(param->param_hdr.length) - sizeof(struct sctp_paramhdr); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* SCTP-AUTH, Section 3.2 6508c2ecf20Sopenharmony_ci * The chunk types for INIT, INIT-ACK, SHUTDOWN-COMPLETE and AUTH 6518c2ecf20Sopenharmony_ci * chunks MUST NOT be listed in the CHUNKS parameter. However, if 6528c2ecf20Sopenharmony_ci * a CHUNKS parameter is received then the types for INIT, INIT-ACK, 6538c2ecf20Sopenharmony_ci * SHUTDOWN-COMPLETE and AUTH chunks MUST be ignored. 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_ci for (i = 0; !found && i < len; i++) { 6568c2ecf20Sopenharmony_ci switch (param->chunks[i]) { 6578c2ecf20Sopenharmony_ci case SCTP_CID_INIT: 6588c2ecf20Sopenharmony_ci case SCTP_CID_INIT_ACK: 6598c2ecf20Sopenharmony_ci case SCTP_CID_SHUTDOWN_COMPLETE: 6608c2ecf20Sopenharmony_ci case SCTP_CID_AUTH: 6618c2ecf20Sopenharmony_ci break; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci default: 6648c2ecf20Sopenharmony_ci if (param->chunks[i] == chunk) 6658c2ecf20Sopenharmony_ci found = 1; 6668c2ecf20Sopenharmony_ci break; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci return found; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci/* Check if peer requested that this chunk is authenticated */ 6748c2ecf20Sopenharmony_ciint sctp_auth_send_cid(enum sctp_cid chunk, const struct sctp_association *asoc) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci if (!asoc) 6778c2ecf20Sopenharmony_ci return 0; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (!asoc->peer.auth_capable) 6808c2ecf20Sopenharmony_ci return 0; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci return __sctp_auth_cid(chunk, asoc->peer.peer_chunks); 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci/* Check if we requested that peer authenticate this chunk. */ 6868c2ecf20Sopenharmony_ciint sctp_auth_recv_cid(enum sctp_cid chunk, const struct sctp_association *asoc) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci if (!asoc) 6898c2ecf20Sopenharmony_ci return 0; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci if (!asoc->peer.auth_capable) 6928c2ecf20Sopenharmony_ci return 0; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci return __sctp_auth_cid(chunk, 6958c2ecf20Sopenharmony_ci (struct sctp_chunks_param *)asoc->c.auth_chunks); 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci/* SCTP-AUTH: Section 6.2: 6998c2ecf20Sopenharmony_ci * The sender MUST calculate the MAC as described in RFC2104 [2] using 7008c2ecf20Sopenharmony_ci * the hash function H as described by the MAC Identifier and the shared 7018c2ecf20Sopenharmony_ci * association key K based on the endpoint pair shared key described by 7028c2ecf20Sopenharmony_ci * the shared key identifier. The 'data' used for the computation of 7038c2ecf20Sopenharmony_ci * the AUTH-chunk is given by the AUTH chunk with its HMAC field set to 7048c2ecf20Sopenharmony_ci * zero (as shown in Figure 6) followed by all chunks that are placed 7058c2ecf20Sopenharmony_ci * after the AUTH chunk in the SCTP packet. 7068c2ecf20Sopenharmony_ci */ 7078c2ecf20Sopenharmony_civoid sctp_auth_calculate_hmac(const struct sctp_association *asoc, 7088c2ecf20Sopenharmony_ci struct sk_buff *skb, struct sctp_auth_chunk *auth, 7098c2ecf20Sopenharmony_ci struct sctp_shared_key *ep_key, gfp_t gfp) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci struct sctp_auth_bytes *asoc_key; 7128c2ecf20Sopenharmony_ci struct crypto_shash *tfm; 7138c2ecf20Sopenharmony_ci __u16 key_id, hmac_id; 7148c2ecf20Sopenharmony_ci unsigned char *end; 7158c2ecf20Sopenharmony_ci int free_key = 0; 7168c2ecf20Sopenharmony_ci __u8 *digest; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* Extract the info we need: 7198c2ecf20Sopenharmony_ci * - hmac id 7208c2ecf20Sopenharmony_ci * - key id 7218c2ecf20Sopenharmony_ci */ 7228c2ecf20Sopenharmony_ci key_id = ntohs(auth->auth_hdr.shkey_id); 7238c2ecf20Sopenharmony_ci hmac_id = ntohs(auth->auth_hdr.hmac_id); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if (key_id == asoc->active_key_id) 7268c2ecf20Sopenharmony_ci asoc_key = asoc->asoc_shared_key; 7278c2ecf20Sopenharmony_ci else { 7288c2ecf20Sopenharmony_ci /* ep_key can't be NULL here */ 7298c2ecf20Sopenharmony_ci asoc_key = sctp_auth_asoc_create_secret(asoc, ep_key, gfp); 7308c2ecf20Sopenharmony_ci if (!asoc_key) 7318c2ecf20Sopenharmony_ci return; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci free_key = 1; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* set up scatter list */ 7378c2ecf20Sopenharmony_ci end = skb_tail_pointer(skb); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci tfm = asoc->ep->auth_hmacs[hmac_id]; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci digest = auth->auth_hdr.hmac; 7428c2ecf20Sopenharmony_ci if (crypto_shash_setkey(tfm, &asoc_key->data[0], asoc_key->len)) 7438c2ecf20Sopenharmony_ci goto free; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci crypto_shash_tfm_digest(tfm, (u8 *)auth, end - (unsigned char *)auth, 7468c2ecf20Sopenharmony_ci digest); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cifree: 7498c2ecf20Sopenharmony_ci if (free_key) 7508c2ecf20Sopenharmony_ci sctp_auth_key_put(asoc_key); 7518c2ecf20Sopenharmony_ci} 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci/* API Helpers */ 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci/* Add a chunk to the endpoint authenticated chunk list */ 7568c2ecf20Sopenharmony_ciint sctp_auth_ep_add_chunkid(struct sctp_endpoint *ep, __u8 chunk_id) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci struct sctp_chunks_param *p = ep->auth_chunk_list; 7598c2ecf20Sopenharmony_ci __u16 nchunks; 7608c2ecf20Sopenharmony_ci __u16 param_len; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci /* If this chunk is already specified, we are done */ 7638c2ecf20Sopenharmony_ci if (__sctp_auth_cid(chunk_id, p)) 7648c2ecf20Sopenharmony_ci return 0; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci /* Check if we can add this chunk to the array */ 7678c2ecf20Sopenharmony_ci param_len = ntohs(p->param_hdr.length); 7688c2ecf20Sopenharmony_ci nchunks = param_len - sizeof(struct sctp_paramhdr); 7698c2ecf20Sopenharmony_ci if (nchunks == SCTP_NUM_CHUNK_TYPES) 7708c2ecf20Sopenharmony_ci return -EINVAL; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci p->chunks[nchunks] = chunk_id; 7738c2ecf20Sopenharmony_ci p->param_hdr.length = htons(param_len + 1); 7748c2ecf20Sopenharmony_ci return 0; 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci/* Add hmac identifires to the endpoint list of supported hmac ids */ 7788c2ecf20Sopenharmony_ciint sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep, 7798c2ecf20Sopenharmony_ci struct sctp_hmacalgo *hmacs) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci int has_sha1 = 0; 7828c2ecf20Sopenharmony_ci __u16 id; 7838c2ecf20Sopenharmony_ci int i; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci /* Scan the list looking for unsupported id. Also make sure that 7868c2ecf20Sopenharmony_ci * SHA1 is specified. 7878c2ecf20Sopenharmony_ci */ 7888c2ecf20Sopenharmony_ci for (i = 0; i < hmacs->shmac_num_idents; i++) { 7898c2ecf20Sopenharmony_ci id = hmacs->shmac_idents[i]; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci if (id > SCTP_AUTH_HMAC_ID_MAX) 7928c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (SCTP_AUTH_HMAC_ID_SHA1 == id) 7958c2ecf20Sopenharmony_ci has_sha1 = 1; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci if (!sctp_hmac_list[id].hmac_name) 7988c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (!has_sha1) 8028c2ecf20Sopenharmony_ci return -EINVAL; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci for (i = 0; i < hmacs->shmac_num_idents; i++) 8058c2ecf20Sopenharmony_ci ep->auth_hmacs_list->hmac_ids[i] = 8068c2ecf20Sopenharmony_ci htons(hmacs->shmac_idents[i]); 8078c2ecf20Sopenharmony_ci ep->auth_hmacs_list->param_hdr.length = 8088c2ecf20Sopenharmony_ci htons(sizeof(struct sctp_paramhdr) + 8098c2ecf20Sopenharmony_ci hmacs->shmac_num_idents * sizeof(__u16)); 8108c2ecf20Sopenharmony_ci return 0; 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci/* Set a new shared key on either endpoint or association. If the 8148c2ecf20Sopenharmony_ci * key with a same ID already exists, replace the key (remove the 8158c2ecf20Sopenharmony_ci * old key and add a new one). 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_ciint sctp_auth_set_key(struct sctp_endpoint *ep, 8188c2ecf20Sopenharmony_ci struct sctp_association *asoc, 8198c2ecf20Sopenharmony_ci struct sctp_authkey *auth_key) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci struct sctp_shared_key *cur_key, *shkey; 8228c2ecf20Sopenharmony_ci struct sctp_auth_bytes *key; 8238c2ecf20Sopenharmony_ci struct list_head *sh_keys; 8248c2ecf20Sopenharmony_ci int replace = 0; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci /* Try to find the given key id to see if 8278c2ecf20Sopenharmony_ci * we are doing a replace, or adding a new key 8288c2ecf20Sopenharmony_ci */ 8298c2ecf20Sopenharmony_ci if (asoc) { 8308c2ecf20Sopenharmony_ci if (!asoc->peer.auth_capable) 8318c2ecf20Sopenharmony_ci return -EACCES; 8328c2ecf20Sopenharmony_ci sh_keys = &asoc->endpoint_shared_keys; 8338c2ecf20Sopenharmony_ci } else { 8348c2ecf20Sopenharmony_ci if (!ep->auth_enable) 8358c2ecf20Sopenharmony_ci return -EACCES; 8368c2ecf20Sopenharmony_ci sh_keys = &ep->endpoint_shared_keys; 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci key_for_each(shkey, sh_keys) { 8408c2ecf20Sopenharmony_ci if (shkey->key_id == auth_key->sca_keynumber) { 8418c2ecf20Sopenharmony_ci replace = 1; 8428c2ecf20Sopenharmony_ci break; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci } 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci cur_key = sctp_auth_shkey_create(auth_key->sca_keynumber, GFP_KERNEL); 8478c2ecf20Sopenharmony_ci if (!cur_key) 8488c2ecf20Sopenharmony_ci return -ENOMEM; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* Create a new key data based on the info passed in */ 8518c2ecf20Sopenharmony_ci key = sctp_auth_create_key(auth_key->sca_keylength, GFP_KERNEL); 8528c2ecf20Sopenharmony_ci if (!key) { 8538c2ecf20Sopenharmony_ci kfree(cur_key); 8548c2ecf20Sopenharmony_ci return -ENOMEM; 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci memcpy(key->data, &auth_key->sca_key[0], auth_key->sca_keylength); 8588c2ecf20Sopenharmony_ci cur_key->key = key; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (!replace) { 8618c2ecf20Sopenharmony_ci list_add(&cur_key->key_list, sh_keys); 8628c2ecf20Sopenharmony_ci return 0; 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci list_del_init(&shkey->key_list); 8668c2ecf20Sopenharmony_ci list_add(&cur_key->key_list, sh_keys); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (asoc && asoc->active_key_id == auth_key->sca_keynumber && 8698c2ecf20Sopenharmony_ci sctp_auth_asoc_init_active_key(asoc, GFP_KERNEL)) { 8708c2ecf20Sopenharmony_ci list_del_init(&cur_key->key_list); 8718c2ecf20Sopenharmony_ci sctp_auth_shkey_release(cur_key); 8728c2ecf20Sopenharmony_ci list_add(&shkey->key_list, sh_keys); 8738c2ecf20Sopenharmony_ci return -ENOMEM; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci sctp_auth_shkey_release(shkey); 8778c2ecf20Sopenharmony_ci return 0; 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ciint sctp_auth_set_active_key(struct sctp_endpoint *ep, 8818c2ecf20Sopenharmony_ci struct sctp_association *asoc, 8828c2ecf20Sopenharmony_ci __u16 key_id) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci struct sctp_shared_key *key; 8858c2ecf20Sopenharmony_ci struct list_head *sh_keys; 8868c2ecf20Sopenharmony_ci int found = 0; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* The key identifier MUST correst to an existing key */ 8898c2ecf20Sopenharmony_ci if (asoc) { 8908c2ecf20Sopenharmony_ci if (!asoc->peer.auth_capable) 8918c2ecf20Sopenharmony_ci return -EACCES; 8928c2ecf20Sopenharmony_ci sh_keys = &asoc->endpoint_shared_keys; 8938c2ecf20Sopenharmony_ci } else { 8948c2ecf20Sopenharmony_ci if (!ep->auth_enable) 8958c2ecf20Sopenharmony_ci return -EACCES; 8968c2ecf20Sopenharmony_ci sh_keys = &ep->endpoint_shared_keys; 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci key_for_each(key, sh_keys) { 9008c2ecf20Sopenharmony_ci if (key->key_id == key_id) { 9018c2ecf20Sopenharmony_ci found = 1; 9028c2ecf20Sopenharmony_ci break; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci if (!found || key->deactivated) 9078c2ecf20Sopenharmony_ci return -EINVAL; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci if (asoc) { 9108c2ecf20Sopenharmony_ci __u16 active_key_id = asoc->active_key_id; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci asoc->active_key_id = key_id; 9138c2ecf20Sopenharmony_ci if (sctp_auth_asoc_init_active_key(asoc, GFP_KERNEL)) { 9148c2ecf20Sopenharmony_ci asoc->active_key_id = active_key_id; 9158c2ecf20Sopenharmony_ci return -ENOMEM; 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci } else 9188c2ecf20Sopenharmony_ci ep->active_key_id = key_id; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci return 0; 9218c2ecf20Sopenharmony_ci} 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ciint sctp_auth_del_key_id(struct sctp_endpoint *ep, 9248c2ecf20Sopenharmony_ci struct sctp_association *asoc, 9258c2ecf20Sopenharmony_ci __u16 key_id) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci struct sctp_shared_key *key; 9288c2ecf20Sopenharmony_ci struct list_head *sh_keys; 9298c2ecf20Sopenharmony_ci int found = 0; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci /* The key identifier MUST NOT be the current active key 9328c2ecf20Sopenharmony_ci * The key identifier MUST correst to an existing key 9338c2ecf20Sopenharmony_ci */ 9348c2ecf20Sopenharmony_ci if (asoc) { 9358c2ecf20Sopenharmony_ci if (!asoc->peer.auth_capable) 9368c2ecf20Sopenharmony_ci return -EACCES; 9378c2ecf20Sopenharmony_ci if (asoc->active_key_id == key_id) 9388c2ecf20Sopenharmony_ci return -EINVAL; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci sh_keys = &asoc->endpoint_shared_keys; 9418c2ecf20Sopenharmony_ci } else { 9428c2ecf20Sopenharmony_ci if (!ep->auth_enable) 9438c2ecf20Sopenharmony_ci return -EACCES; 9448c2ecf20Sopenharmony_ci if (ep->active_key_id == key_id) 9458c2ecf20Sopenharmony_ci return -EINVAL; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci sh_keys = &ep->endpoint_shared_keys; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci key_for_each(key, sh_keys) { 9518c2ecf20Sopenharmony_ci if (key->key_id == key_id) { 9528c2ecf20Sopenharmony_ci found = 1; 9538c2ecf20Sopenharmony_ci break; 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci if (!found) 9588c2ecf20Sopenharmony_ci return -EINVAL; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci /* Delete the shared key */ 9618c2ecf20Sopenharmony_ci list_del_init(&key->key_list); 9628c2ecf20Sopenharmony_ci sctp_auth_shkey_release(key); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci return 0; 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ciint sctp_auth_deact_key_id(struct sctp_endpoint *ep, 9688c2ecf20Sopenharmony_ci struct sctp_association *asoc, __u16 key_id) 9698c2ecf20Sopenharmony_ci{ 9708c2ecf20Sopenharmony_ci struct sctp_shared_key *key; 9718c2ecf20Sopenharmony_ci struct list_head *sh_keys; 9728c2ecf20Sopenharmony_ci int found = 0; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci /* The key identifier MUST NOT be the current active key 9758c2ecf20Sopenharmony_ci * The key identifier MUST correst to an existing key 9768c2ecf20Sopenharmony_ci */ 9778c2ecf20Sopenharmony_ci if (asoc) { 9788c2ecf20Sopenharmony_ci if (!asoc->peer.auth_capable) 9798c2ecf20Sopenharmony_ci return -EACCES; 9808c2ecf20Sopenharmony_ci if (asoc->active_key_id == key_id) 9818c2ecf20Sopenharmony_ci return -EINVAL; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci sh_keys = &asoc->endpoint_shared_keys; 9848c2ecf20Sopenharmony_ci } else { 9858c2ecf20Sopenharmony_ci if (!ep->auth_enable) 9868c2ecf20Sopenharmony_ci return -EACCES; 9878c2ecf20Sopenharmony_ci if (ep->active_key_id == key_id) 9888c2ecf20Sopenharmony_ci return -EINVAL; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci sh_keys = &ep->endpoint_shared_keys; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci key_for_each(key, sh_keys) { 9948c2ecf20Sopenharmony_ci if (key->key_id == key_id) { 9958c2ecf20Sopenharmony_ci found = 1; 9968c2ecf20Sopenharmony_ci break; 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (!found) 10018c2ecf20Sopenharmony_ci return -EINVAL; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci /* refcnt == 1 and !list_empty mean it's not being used anywhere 10048c2ecf20Sopenharmony_ci * and deactivated will be set, so it's time to notify userland 10058c2ecf20Sopenharmony_ci * that this shkey can be freed. 10068c2ecf20Sopenharmony_ci */ 10078c2ecf20Sopenharmony_ci if (asoc && !list_empty(&key->key_list) && 10088c2ecf20Sopenharmony_ci refcount_read(&key->refcnt) == 1) { 10098c2ecf20Sopenharmony_ci struct sctp_ulpevent *ev; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci ev = sctp_ulpevent_make_authkey(asoc, key->key_id, 10128c2ecf20Sopenharmony_ci SCTP_AUTH_FREE_KEY, GFP_KERNEL); 10138c2ecf20Sopenharmony_ci if (ev) 10148c2ecf20Sopenharmony_ci asoc->stream.si->enqueue_event(&asoc->ulpq, ev); 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci key->deactivated = 1; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci return 0; 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ciint sctp_auth_init(struct sctp_endpoint *ep, gfp_t gfp) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci int err = -ENOMEM; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci /* Allocate space for HMACS and CHUNKS authentication 10278c2ecf20Sopenharmony_ci * variables. There are arrays that we encode directly 10288c2ecf20Sopenharmony_ci * into parameters to make the rest of the operations easier. 10298c2ecf20Sopenharmony_ci */ 10308c2ecf20Sopenharmony_ci if (!ep->auth_hmacs_list) { 10318c2ecf20Sopenharmony_ci struct sctp_hmac_algo_param *auth_hmacs; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci auth_hmacs = kzalloc(struct_size(auth_hmacs, hmac_ids, 10348c2ecf20Sopenharmony_ci SCTP_AUTH_NUM_HMACS), gfp); 10358c2ecf20Sopenharmony_ci if (!auth_hmacs) 10368c2ecf20Sopenharmony_ci goto nomem; 10378c2ecf20Sopenharmony_ci /* Initialize the HMACS parameter. 10388c2ecf20Sopenharmony_ci * SCTP-AUTH: Section 3.3 10398c2ecf20Sopenharmony_ci * Every endpoint supporting SCTP chunk authentication MUST 10408c2ecf20Sopenharmony_ci * support the HMAC based on the SHA-1 algorithm. 10418c2ecf20Sopenharmony_ci */ 10428c2ecf20Sopenharmony_ci auth_hmacs->param_hdr.type = SCTP_PARAM_HMAC_ALGO; 10438c2ecf20Sopenharmony_ci auth_hmacs->param_hdr.length = 10448c2ecf20Sopenharmony_ci htons(sizeof(struct sctp_paramhdr) + 2); 10458c2ecf20Sopenharmony_ci auth_hmacs->hmac_ids[0] = htons(SCTP_AUTH_HMAC_ID_SHA1); 10468c2ecf20Sopenharmony_ci ep->auth_hmacs_list = auth_hmacs; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (!ep->auth_chunk_list) { 10508c2ecf20Sopenharmony_ci struct sctp_chunks_param *auth_chunks; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci auth_chunks = kzalloc(sizeof(*auth_chunks) + 10538c2ecf20Sopenharmony_ci SCTP_NUM_CHUNK_TYPES, gfp); 10548c2ecf20Sopenharmony_ci if (!auth_chunks) 10558c2ecf20Sopenharmony_ci goto nomem; 10568c2ecf20Sopenharmony_ci /* Initialize the CHUNKS parameter */ 10578c2ecf20Sopenharmony_ci auth_chunks->param_hdr.type = SCTP_PARAM_CHUNKS; 10588c2ecf20Sopenharmony_ci auth_chunks->param_hdr.length = 10598c2ecf20Sopenharmony_ci htons(sizeof(struct sctp_paramhdr)); 10608c2ecf20Sopenharmony_ci ep->auth_chunk_list = auth_chunks; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci /* Allocate and initialize transorms arrays for supported 10648c2ecf20Sopenharmony_ci * HMACs. 10658c2ecf20Sopenharmony_ci */ 10668c2ecf20Sopenharmony_ci err = sctp_auth_init_hmacs(ep, gfp); 10678c2ecf20Sopenharmony_ci if (err) 10688c2ecf20Sopenharmony_ci goto nomem; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci return 0; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_cinomem: 10738c2ecf20Sopenharmony_ci /* Free all allocations */ 10748c2ecf20Sopenharmony_ci kfree(ep->auth_hmacs_list); 10758c2ecf20Sopenharmony_ci kfree(ep->auth_chunk_list); 10768c2ecf20Sopenharmony_ci ep->auth_hmacs_list = NULL; 10778c2ecf20Sopenharmony_ci ep->auth_chunk_list = NULL; 10788c2ecf20Sopenharmony_ci return err; 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_civoid sctp_auth_free(struct sctp_endpoint *ep) 10828c2ecf20Sopenharmony_ci{ 10838c2ecf20Sopenharmony_ci kfree(ep->auth_hmacs_list); 10848c2ecf20Sopenharmony_ci kfree(ep->auth_chunk_list); 10858c2ecf20Sopenharmony_ci ep->auth_hmacs_list = NULL; 10868c2ecf20Sopenharmony_ci ep->auth_chunk_list = NULL; 10878c2ecf20Sopenharmony_ci sctp_auth_destroy_hmacs(ep->auth_hmacs); 10888c2ecf20Sopenharmony_ci ep->auth_hmacs = NULL; 10898c2ecf20Sopenharmony_ci} 1090