mirror of https://github.com/torvalds/linux.git
sctp: Use HMAC-SHA1 and HMAC-SHA256 library for chunk authentication
For SCTP chunk authentication, use the HMAC-SHA1 and HMAC-SHA256 library functions instead of crypto_shash. This is simpler and faster. There's no longer any need to pre-allocate 'crypto_shash' objects; the SCTP code now simply calls into the HMAC code directly. As part of this, make SCTP always support both HMAC-SHA1 and HMAC-SHA256. Previously, it only guaranteed support for HMAC-SHA1. However, HMAC-SHA256 tended to be supported too anyway, as it was supported if CONFIG_CRYPTO_SHA256 was enabled elsewhere in the kconfig. Acked-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: Eric Biggers <ebiggers@kernel.org> Link: https://patch.msgid.link/20250818205426.30222-4-ebiggers@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
dd91c79e4f
commit
bf40785fa4
|
|
@ -22,16 +22,11 @@ struct sctp_endpoint;
|
|||
struct sctp_association;
|
||||
struct sctp_authkey;
|
||||
struct sctp_hmacalgo;
|
||||
struct crypto_shash;
|
||||
|
||||
/*
|
||||
* Define a generic struct that will hold all the info
|
||||
* necessary for an HMAC transform
|
||||
*/
|
||||
/* Defines an HMAC algorithm supported by SCTP chunk authentication */
|
||||
struct sctp_hmac {
|
||||
__u16 hmac_id; /* one of the above ids */
|
||||
char *hmac_name; /* name for loading */
|
||||
__u16 hmac_len; /* length of the signature */
|
||||
__u16 hmac_id; /* one of SCTP_AUTH_HMAC_ID_* */
|
||||
__u16 hmac_len; /* length of the HMAC value in bytes */
|
||||
};
|
||||
|
||||
/* This is generic structure that containst authentication bytes used
|
||||
|
|
@ -78,9 +73,9 @@ int sctp_auth_asoc_copy_shkeys(const struct sctp_endpoint *ep,
|
|||
struct sctp_association *asoc,
|
||||
gfp_t gfp);
|
||||
int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp);
|
||||
void sctp_auth_destroy_hmacs(struct crypto_shash *auth_hmacs[]);
|
||||
struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id);
|
||||
struct sctp_hmac *sctp_auth_asoc_get_hmac(const struct sctp_association *asoc);
|
||||
const struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id);
|
||||
const struct sctp_hmac *
|
||||
sctp_auth_asoc_get_hmac(const struct sctp_association *asoc);
|
||||
void sctp_auth_asoc_set_default_hmac(struct sctp_association *asoc,
|
||||
struct sctp_hmac_algo_param *hmacs);
|
||||
int sctp_auth_asoc_verify_hmac_id(const struct sctp_association *asoc,
|
||||
|
|
|
|||
|
|
@ -417,16 +417,12 @@ enum {
|
|||
SCTP_AUTH_HMAC_ID_RESERVED_0,
|
||||
SCTP_AUTH_HMAC_ID_SHA1,
|
||||
SCTP_AUTH_HMAC_ID_RESERVED_2,
|
||||
#if defined (CONFIG_CRYPTO_SHA256) || defined (CONFIG_CRYPTO_SHA256_MODULE)
|
||||
SCTP_AUTH_HMAC_ID_SHA256,
|
||||
#endif
|
||||
__SCTP_AUTH_HMAC_MAX
|
||||
};
|
||||
|
||||
#define SCTP_AUTH_HMAC_ID_MAX __SCTP_AUTH_HMAC_MAX - 1
|
||||
#define SCTP_AUTH_NUM_HMACS __SCTP_AUTH_HMAC_MAX
|
||||
#define SCTP_SHA1_SIG_SIZE 20
|
||||
#define SCTP_SHA256_SIG_SIZE 32
|
||||
|
||||
/* SCTP-AUTH, Section 3.2
|
||||
* The chunk types for INIT, INIT-ACK, SHUTDOWN-COMPLETE and AUTH chunks
|
||||
|
|
|
|||
|
|
@ -1329,11 +1329,6 @@ struct sctp_endpoint {
|
|||
/* rcvbuf acct. policy. */
|
||||
__u32 rcvbuf_policy;
|
||||
|
||||
/* SCTP AUTH: array of the HMACs that will be allocated
|
||||
* we need this per association so that we don't serialize
|
||||
*/
|
||||
struct crypto_shash **auth_hmacs;
|
||||
|
||||
/* SCTP-AUTH: hmacs for the endpoint encoded into parameter */
|
||||
struct sctp_hmac_algo_param *auth_hmacs_list;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ menuconfig IP_SCTP
|
|||
tristate "The SCTP Protocol"
|
||||
depends on INET
|
||||
depends on IPV6 || IPV6=n
|
||||
select CRYPTO
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_SHA1
|
||||
select CRYPTO_LIB_SHA1
|
||||
select CRYPTO_LIB_SHA256
|
||||
select CRYPTO_LIB_UTILS
|
||||
select NET_CRC32C
|
||||
select NET_UDP_TUNNEL
|
||||
help
|
||||
|
|
@ -79,15 +79,17 @@ config SCTP_COOKIE_HMAC_MD5
|
|||
bool "Enable optional MD5 hmac cookie generation"
|
||||
help
|
||||
Enable optional MD5 hmac based SCTP cookie generation
|
||||
select CRYPTO_HMAC if SCTP_COOKIE_HMAC_MD5
|
||||
select CRYPTO_MD5 if SCTP_COOKIE_HMAC_MD5
|
||||
select CRYPTO
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_MD5
|
||||
|
||||
config SCTP_COOKIE_HMAC_SHA1
|
||||
bool "Enable optional SHA1 hmac cookie generation"
|
||||
help
|
||||
Enable optional SHA1 hmac based SCTP cookie generation
|
||||
select CRYPTO_HMAC if SCTP_COOKIE_HMAC_SHA1
|
||||
select CRYPTO_SHA1 if SCTP_COOKIE_HMAC_SHA1
|
||||
select CRYPTO
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_SHA1
|
||||
|
||||
config INET_SCTP_DIAG
|
||||
depends on INET_DIAG
|
||||
|
|
|
|||
166
net/sctp/auth.c
166
net/sctp/auth.c
|
|
@ -12,36 +12,37 @@
|
|||
* Vlad Yasevich <vladislav.yasevich@hp.com>
|
||||
*/
|
||||
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/sha1.h>
|
||||
#include <crypto/sha2.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <net/sctp/sctp.h>
|
||||
#include <net/sctp/auth.h>
|
||||
|
||||
static struct sctp_hmac sctp_hmac_list[SCTP_AUTH_NUM_HMACS] = {
|
||||
static const struct sctp_hmac sctp_hmac_list[SCTP_AUTH_NUM_HMACS] = {
|
||||
{
|
||||
/* id 0 is reserved. as all 0 */
|
||||
.hmac_id = SCTP_AUTH_HMAC_ID_RESERVED_0,
|
||||
},
|
||||
{
|
||||
.hmac_id = SCTP_AUTH_HMAC_ID_SHA1,
|
||||
.hmac_name = "hmac(sha1)",
|
||||
.hmac_len = SCTP_SHA1_SIG_SIZE,
|
||||
.hmac_len = SHA1_DIGEST_SIZE,
|
||||
},
|
||||
{
|
||||
/* id 2 is reserved as well */
|
||||
.hmac_id = SCTP_AUTH_HMAC_ID_RESERVED_2,
|
||||
},
|
||||
#if IS_ENABLED(CONFIG_CRYPTO_SHA256)
|
||||
{
|
||||
.hmac_id = SCTP_AUTH_HMAC_ID_SHA256,
|
||||
.hmac_name = "hmac(sha256)",
|
||||
.hmac_len = SCTP_SHA256_SIG_SIZE,
|
||||
.hmac_len = SHA256_DIGEST_SIZE,
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
static bool sctp_hmac_supported(__u16 hmac_id)
|
||||
{
|
||||
return hmac_id < ARRAY_SIZE(sctp_hmac_list) &&
|
||||
sctp_hmac_list[hmac_id].hmac_len != 0;
|
||||
}
|
||||
|
||||
void sctp_auth_key_put(struct sctp_auth_bytes *key)
|
||||
{
|
||||
|
|
@ -444,76 +445,7 @@ struct sctp_shared_key *sctp_auth_get_shkey(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize all the possible digest transforms that we can use. Right
|
||||
* now, the supported digests are SHA1 and SHA256. We do this here once
|
||||
* because of the restrictiong that transforms may only be allocated in
|
||||
* user context. This forces us to pre-allocated all possible transforms
|
||||
* at the endpoint init time.
|
||||
*/
|
||||
int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp)
|
||||
{
|
||||
struct crypto_shash *tfm = NULL;
|
||||
__u16 id;
|
||||
|
||||
/* If the transforms are already allocated, we are done */
|
||||
if (ep->auth_hmacs)
|
||||
return 0;
|
||||
|
||||
/* Allocated the array of pointers to transorms */
|
||||
ep->auth_hmacs = kcalloc(SCTP_AUTH_NUM_HMACS,
|
||||
sizeof(struct crypto_shash *),
|
||||
gfp);
|
||||
if (!ep->auth_hmacs)
|
||||
return -ENOMEM;
|
||||
|
||||
for (id = 0; id < SCTP_AUTH_NUM_HMACS; id++) {
|
||||
|
||||
/* See is we support the id. Supported IDs have name and
|
||||
* length fields set, so that we can allocated and use
|
||||
* them. We can safely just check for name, for without the
|
||||
* name, we can't allocate the TFM.
|
||||
*/
|
||||
if (!sctp_hmac_list[id].hmac_name)
|
||||
continue;
|
||||
|
||||
/* If this TFM has been allocated, we are all set */
|
||||
if (ep->auth_hmacs[id])
|
||||
continue;
|
||||
|
||||
/* Allocate the ID */
|
||||
tfm = crypto_alloc_shash(sctp_hmac_list[id].hmac_name, 0, 0);
|
||||
if (IS_ERR(tfm))
|
||||
goto out_err;
|
||||
|
||||
ep->auth_hmacs[id] = tfm;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
/* Clean up any successful allocations */
|
||||
sctp_auth_destroy_hmacs(ep->auth_hmacs);
|
||||
ep->auth_hmacs = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Destroy the hmac tfm array */
|
||||
void sctp_auth_destroy_hmacs(struct crypto_shash *auth_hmacs[])
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!auth_hmacs)
|
||||
return;
|
||||
|
||||
for (i = 0; i < SCTP_AUTH_NUM_HMACS; i++) {
|
||||
crypto_free_shash(auth_hmacs[i]);
|
||||
}
|
||||
kfree(auth_hmacs);
|
||||
}
|
||||
|
||||
|
||||
struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id)
|
||||
const struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id)
|
||||
{
|
||||
return &sctp_hmac_list[hmac_id];
|
||||
}
|
||||
|
|
@ -521,7 +453,8 @@ struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id)
|
|||
/* Get an hmac description information that we can use to build
|
||||
* the AUTH chunk
|
||||
*/
|
||||
struct sctp_hmac *sctp_auth_asoc_get_hmac(const struct sctp_association *asoc)
|
||||
const struct sctp_hmac *
|
||||
sctp_auth_asoc_get_hmac(const struct sctp_association *asoc)
|
||||
{
|
||||
struct sctp_hmac_algo_param *hmacs;
|
||||
__u16 n_elt;
|
||||
|
|
@ -543,26 +476,10 @@ struct sctp_hmac *sctp_auth_asoc_get_hmac(const struct sctp_association *asoc)
|
|||
sizeof(struct sctp_paramhdr)) >> 1;
|
||||
for (i = 0; i < n_elt; i++) {
|
||||
id = ntohs(hmacs->hmac_ids[i]);
|
||||
|
||||
/* Check the id is in the supported range. And
|
||||
* see if we support the id. Supported IDs have name and
|
||||
* length fields set, so that we can allocate and use
|
||||
* them. We can safely just check for name, for without the
|
||||
* name, we can't allocate the TFM.
|
||||
*/
|
||||
if (id > SCTP_AUTH_HMAC_ID_MAX ||
|
||||
!sctp_hmac_list[id].hmac_name) {
|
||||
id = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (id == 0)
|
||||
return NULL;
|
||||
|
||||
if (sctp_hmac_supported(id))
|
||||
return &sctp_hmac_list[id];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int __sctp_auth_find_hmacid(__be16 *hmacs, int n_elts, __be16 hmac_id)
|
||||
|
|
@ -606,7 +523,6 @@ int sctp_auth_asoc_verify_hmac_id(const struct sctp_association *asoc,
|
|||
void sctp_auth_asoc_set_default_hmac(struct sctp_association *asoc,
|
||||
struct sctp_hmac_algo_param *hmacs)
|
||||
{
|
||||
struct sctp_endpoint *ep;
|
||||
__u16 id;
|
||||
int i;
|
||||
int n_params;
|
||||
|
|
@ -617,16 +533,9 @@ void sctp_auth_asoc_set_default_hmac(struct sctp_association *asoc,
|
|||
|
||||
n_params = (ntohs(hmacs->param_hdr.length) -
|
||||
sizeof(struct sctp_paramhdr)) >> 1;
|
||||
ep = asoc->ep;
|
||||
for (i = 0; i < n_params; i++) {
|
||||
id = ntohs(hmacs->hmac_ids[i]);
|
||||
|
||||
/* Check the id is in the supported range */
|
||||
if (id > SCTP_AUTH_HMAC_ID_MAX)
|
||||
continue;
|
||||
|
||||
/* If this TFM has been allocated, use this id */
|
||||
if (ep->auth_hmacs[id]) {
|
||||
if (sctp_hmac_supported(id)) {
|
||||
asoc->default_hmac_id = id;
|
||||
break;
|
||||
}
|
||||
|
|
@ -709,10 +618,9 @@ void sctp_auth_calculate_hmac(const struct sctp_association *asoc,
|
|||
struct sctp_shared_key *ep_key, gfp_t gfp)
|
||||
{
|
||||
struct sctp_auth_bytes *asoc_key;
|
||||
struct crypto_shash *tfm;
|
||||
__u16 key_id, hmac_id;
|
||||
unsigned char *end;
|
||||
int free_key = 0;
|
||||
size_t data_len;
|
||||
__u8 *digest;
|
||||
|
||||
/* Extract the info we need:
|
||||
|
|
@ -733,19 +641,17 @@ void sctp_auth_calculate_hmac(const struct sctp_association *asoc,
|
|||
free_key = 1;
|
||||
}
|
||||
|
||||
/* set up scatter list */
|
||||
end = skb_tail_pointer(skb);
|
||||
|
||||
tfm = asoc->ep->auth_hmacs[hmac_id];
|
||||
|
||||
data_len = skb_tail_pointer(skb) - (unsigned char *)auth;
|
||||
digest = (u8 *)(&auth->auth_hdr + 1);
|
||||
if (crypto_shash_setkey(tfm, &asoc_key->data[0], asoc_key->len))
|
||||
goto free;
|
||||
if (hmac_id == SCTP_AUTH_HMAC_ID_SHA1) {
|
||||
hmac_sha1_usingrawkey(asoc_key->data, asoc_key->len,
|
||||
(const u8 *)auth, data_len, digest);
|
||||
} else {
|
||||
WARN_ON_ONCE(hmac_id != SCTP_AUTH_HMAC_ID_SHA256);
|
||||
hmac_sha256_usingrawkey(asoc_key->data, asoc_key->len,
|
||||
(const u8 *)auth, data_len, digest);
|
||||
}
|
||||
|
||||
crypto_shash_tfm_digest(tfm, (u8 *)auth, end - (unsigned char *)auth,
|
||||
digest);
|
||||
|
||||
free:
|
||||
if (free_key)
|
||||
sctp_auth_key_put(asoc_key);
|
||||
}
|
||||
|
|
@ -788,14 +694,11 @@ int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep,
|
|||
for (i = 0; i < hmacs->shmac_num_idents; i++) {
|
||||
id = hmacs->shmac_idents[i];
|
||||
|
||||
if (id > SCTP_AUTH_HMAC_ID_MAX)
|
||||
if (!sctp_hmac_supported(id))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (SCTP_AUTH_HMAC_ID_SHA1 == id)
|
||||
has_sha1 = 1;
|
||||
|
||||
if (!sctp_hmac_list[id].hmac_name)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!has_sha1)
|
||||
|
|
@ -1021,8 +924,6 @@ int sctp_auth_deact_key_id(struct sctp_endpoint *ep,
|
|||
|
||||
int sctp_auth_init(struct sctp_endpoint *ep, gfp_t gfp)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
|
||||
/* Allocate space for HMACS and CHUNKS authentication
|
||||
* variables. There are arrays that we encode directly
|
||||
* into parameters to make the rest of the operations easier.
|
||||
|
|
@ -1060,13 +961,6 @@ int sctp_auth_init(struct sctp_endpoint *ep, gfp_t gfp)
|
|||
ep->auth_chunk_list = auth_chunks;
|
||||
}
|
||||
|
||||
/* Allocate and initialize transorms arrays for supported
|
||||
* HMACs.
|
||||
*/
|
||||
err = sctp_auth_init_hmacs(ep, gfp);
|
||||
if (err)
|
||||
goto nomem;
|
||||
|
||||
return 0;
|
||||
|
||||
nomem:
|
||||
|
|
@ -1075,7 +969,7 @@ int sctp_auth_init(struct sctp_endpoint *ep, gfp_t gfp)
|
|||
kfree(ep->auth_chunk_list);
|
||||
ep->auth_hmacs_list = NULL;
|
||||
ep->auth_chunk_list = NULL;
|
||||
return err;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void sctp_auth_free(struct sctp_endpoint *ep)
|
||||
|
|
@ -1084,6 +978,4 @@ void sctp_auth_free(struct sctp_endpoint *ep)
|
|||
kfree(ep->auth_chunk_list);
|
||||
ep->auth_hmacs_list = NULL;
|
||||
ep->auth_chunk_list = NULL;
|
||||
sctp_auth_destroy_hmacs(ep->auth_hmacs);
|
||||
ep->auth_hmacs = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,7 +184,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
|
|||
* DATA.
|
||||
*/
|
||||
if (sctp_auth_send_cid(SCTP_CID_DATA, asoc)) {
|
||||
struct sctp_hmac *hmac_desc = sctp_auth_asoc_get_hmac(asoc);
|
||||
const struct sctp_hmac *hmac_desc =
|
||||
sctp_auth_asoc_get_hmac(asoc);
|
||||
|
||||
if (hmac_desc)
|
||||
max_data -= SCTP_PAD4(sizeof(struct sctp_auth_chunk) +
|
||||
|
|
|
|||
|
|
@ -1320,7 +1320,7 @@ struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc,
|
|||
__u16 key_id)
|
||||
{
|
||||
struct sctp_authhdr auth_hdr;
|
||||
struct sctp_hmac *hmac_desc;
|
||||
const struct sctp_hmac *hmac_desc;
|
||||
struct sctp_chunk *retval;
|
||||
|
||||
/* Get the first hmac that the peer told us to use */
|
||||
|
|
|
|||
|
|
@ -4362,7 +4362,7 @@ static enum sctp_ierror sctp_sf_authenticate(
|
|||
struct sctp_shared_key *sh_key = NULL;
|
||||
struct sctp_authhdr *auth_hdr;
|
||||
__u8 *save_digest, *digest;
|
||||
struct sctp_hmac *hmac;
|
||||
const struct sctp_hmac *hmac;
|
||||
unsigned int sig_len;
|
||||
__u16 key_id;
|
||||
|
||||
|
|
|
|||
|
|
@ -9581,16 +9581,6 @@ static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
/* New ep's auth_hmacs should be set if old ep's is set, in case
|
||||
* that net->sctp.auth_enable has been changed to 0 by users and
|
||||
* new ep's auth_hmacs couldn't be set in sctp_endpoint_init().
|
||||
*/
|
||||
if (oldsp->ep->auth_hmacs) {
|
||||
err = sctp_auth_init_hmacs(newsp->ep, GFP_KERNEL);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
sctp_auto_asconf_init(newsp);
|
||||
|
||||
/* Move any messages in the old socket's receive queue that are for the
|
||||
|
|
|
|||
Loading…
Reference in New Issue