]> www.infradead.org Git - users/willy/linux.git/commitdiff
sctp: Use HMAC-SHA1 and HMAC-SHA256 library for chunk authentication
authorEric Biggers <ebiggers@kernel.org>
Mon, 18 Aug 2025 20:54:24 +0000 (13:54 -0700)
committerJakub Kicinski <kuba@kernel.org>
Wed, 20 Aug 2025 02:36:25 +0000 (19:36 -0700)
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>
include/net/sctp/auth.h
include/net/sctp/constants.h
include/net/sctp/structs.h
net/sctp/Kconfig
net/sctp/auth.c
net/sctp/chunk.c
net/sctp/sm_make_chunk.c
net/sctp/sm_statefuns.c
net/sctp/socket.c

index d4b3b2dcd15b733fba33fa3f5c83b4559015d1b2..3d5879e08e78a12f8e9ab0a266aea051b0e083ef 100644 (file)
@@ -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,
index 5859e0a16a584aa6b128e2776ef94a0ee309f6bc..8e0f4c4f7750662e6da367fe77e50ea70c1af54e 100644 (file)
@@ -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
index 8a540ad9b5090ed8e9a9e7b54fbe9a1f4d57bce0..6be6aec25731eca8319254627a2d8ee55447cbcc 100644 (file)
@@ -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;
 
index 24d5a35ce894ae9cc856dc00775ef0076a75727c..09c77b4d161b12d5573d0d38af96e297034eb8c1 100644 (file)
@@ -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
index c58fffc86a0c2d23d796cc8371cc3467834aa5ea..82aad477590e2ec17ece00806dd8aeeaf0fddf70 100644 (file)
  *   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 (sctp_hmac_supported(id))
+                       return &sctp_hmac_list[id];
        }
-
-       if (id == 0)
-               return NULL;
-
-       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;
-
-       crypto_shash_tfm_digest(tfm, (u8 *)auth, end - (unsigned char *)auth,
-                               digest);
+       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);
+       }
 
-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 @@ nomem:
        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;
 }
index fd4f8243cc35fed0442fb4b4c85b7049ee88c64f..c655b571ca01b6d3c494a7470fa8ee3877a0c359 100644 (file)
@@ -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) +
index d099b605e44a7ff62067b8b9034b20debcabea26..a1a3c8494c5d22814fb9ec8bae06447cd76e189e 100644 (file)
@@ -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 */
index d4d5b14b49b3f5f6d102c7b7df6e1d6ef030da67..4cb8f393434d0c0b106fbe6fc0f93e5b7cd69708 100644 (file)
@@ -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;
 
index 4921416434f9a37ddce9a18efca0a4c23ba4967f..0292881a847ca0ed7a35be30f82717465c444ac0 100644 (file)
@@ -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