mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-05 14:40:12 -04:00
Merge branch 'sctp-convert-to-use-crypto-lib-and-upgrade-cookie-auth'
Eric Biggers says: ==================== sctp: Convert to use crypto lib, and upgrade cookie auth This series converts SCTP chunk and cookie authentication to use the crypto library API instead of crypto_shash. This is much simpler (the diffstat should speak for itself), and also faster too. In addition, this series upgrades the cookie authentication to use HMAC-SHA256. I've tested that kernels with this series applied can continue to communicate using SCTP with older ones, in either direction, using any choice of None, HMAC-SHA1, or HMAC-SHA256 chunk authentication. ==================== Link: https://patch.msgid.link/20250818205426.30222-1-ebiggers@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -3508,16 +3508,10 @@ cookie_hmac_alg - STRING
|
||||
a listening sctp socket to a connecting client in the INIT-ACK chunk.
|
||||
Valid values are:
|
||||
|
||||
* md5
|
||||
* sha1
|
||||
* sha256
|
||||
* none
|
||||
|
||||
Ability to assign md5 or sha1 as the selected alg is predicated on the
|
||||
configuration of those algorithms at build time (CONFIG_CRYPTO_MD5 and
|
||||
CONFIG_CRYPTO_SHA1).
|
||||
|
||||
Default: Dependent on configuration. MD5 if available, else SHA1 if
|
||||
available, else none.
|
||||
Default: sha256
|
||||
|
||||
rcvbuf_policy - INTEGER
|
||||
Determines if the receive buffer is attributed to the socket or to
|
||||
|
||||
@@ -75,8 +75,8 @@ struct netns_sctp {
|
||||
/* Whether Cookie Preservative is enabled(1) or not(0) */
|
||||
int cookie_preserve_enable;
|
||||
|
||||
/* The namespace default hmac alg */
|
||||
char *sctp_hmac_alg;
|
||||
/* Whether cookie authentication is enabled(1) or not(0) */
|
||||
int cookie_auth_enable;
|
||||
|
||||
/* Valid.Cookie.Life - 60 seconds */
|
||||
unsigned int valid_cookie_life;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -296,9 +296,8 @@ enum { SCTP_MAX_GABS = 16 };
|
||||
*/
|
||||
#define SCTP_DEFAULT_MINSEGMENT 512 /* MTU size ... if no mtu disc */
|
||||
|
||||
#define SCTP_SECRET_SIZE 32 /* Number of octets in a 256 bits. */
|
||||
|
||||
#define SCTP_SIGNATURE_SIZE 20 /* size of a SLA-1 signature */
|
||||
#define SCTP_COOKIE_KEY_SIZE 32 /* size of cookie HMAC key */
|
||||
#define SCTP_COOKIE_MAC_SIZE 32 /* size of HMAC field in cookies */
|
||||
|
||||
#define SCTP_COOKIE_MULTIPLE 32 /* Pad out our cookie to make our hash
|
||||
* functions simpler to write.
|
||||
@@ -417,16 +416,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
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#ifndef __sctp_structs_h__
|
||||
#define __sctp_structs_h__
|
||||
|
||||
#include <crypto/sha2.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/generic-radix-tree.h>
|
||||
#include <linux/rhashtable-types.h>
|
||||
@@ -68,7 +69,6 @@ struct sctp_outq;
|
||||
struct sctp_bind_addr;
|
||||
struct sctp_ulpq;
|
||||
struct sctp_ep_common;
|
||||
struct crypto_shash;
|
||||
struct sctp_stream;
|
||||
|
||||
|
||||
@@ -155,10 +155,6 @@ struct sctp_sock {
|
||||
/* PF_ family specific functions. */
|
||||
struct sctp_pf *pf;
|
||||
|
||||
/* Access to HMAC transform. */
|
||||
struct crypto_shash *hmac;
|
||||
char *sctp_hmac_alg;
|
||||
|
||||
/* What is our base endpointer? */
|
||||
struct sctp_endpoint *ep;
|
||||
|
||||
@@ -227,7 +223,8 @@ struct sctp_sock {
|
||||
frag_interleave:1,
|
||||
recvrcvinfo:1,
|
||||
recvnxtinfo:1,
|
||||
data_ready_signalled:1;
|
||||
data_ready_signalled:1,
|
||||
cookie_auth_enable:1;
|
||||
|
||||
atomic_t pd_mode;
|
||||
|
||||
@@ -335,7 +332,7 @@ struct sctp_cookie {
|
||||
|
||||
/* The format of our cookie that we send to our peer. */
|
||||
struct sctp_signed_cookie {
|
||||
__u8 signature[SCTP_SECRET_SIZE];
|
||||
__u8 mac[SCTP_COOKIE_MAC_SIZE];
|
||||
__u32 __pad; /* force sctp_cookie alignment to 64 bits */
|
||||
struct sctp_cookie c;
|
||||
} __packed;
|
||||
@@ -1307,33 +1304,15 @@ struct sctp_endpoint {
|
||||
/* This is really a list of struct sctp_association entries. */
|
||||
struct list_head asocs;
|
||||
|
||||
/* Secret Key: A secret key used by this endpoint to compute
|
||||
* the MAC. This SHOULD be a cryptographic quality
|
||||
* random number with a sufficient length.
|
||||
* Discussion in [RFC1750] can be helpful in
|
||||
* selection of the key.
|
||||
*/
|
||||
__u8 secret_key[SCTP_SECRET_SIZE];
|
||||
/* Cookie authentication key used by this endpoint */
|
||||
struct hmac_sha256_key cookie_auth_key;
|
||||
|
||||
/* digest: This is a digest of the sctp cookie. This field is
|
||||
* only used on the receive path when we try to validate
|
||||
* that the cookie has not been tampered with. We put
|
||||
* this here so we pre-allocate this once and can re-use
|
||||
* on every receive.
|
||||
*/
|
||||
__u8 *digest;
|
||||
|
||||
/* sendbuf acct. policy. */
|
||||
__u32 sndbuf_policy;
|
||||
|
||||
/* 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
|
||||
@@ -49,46 +49,25 @@ config SCTP_DBG_OBJCNT
|
||||
'cat /proc/net/sctp/sctp_dbg_objcnt'
|
||||
|
||||
If unsure, say N
|
||||
|
||||
choice
|
||||
prompt "Default SCTP cookie HMAC encoding"
|
||||
default SCTP_DEFAULT_COOKIE_HMAC_MD5
|
||||
prompt "Default SCTP cookie authentication method"
|
||||
default SCTP_DEFAULT_COOKIE_HMAC_SHA256
|
||||
help
|
||||
This option sets the default sctp cookie hmac algorithm
|
||||
when in doubt select 'md5'
|
||||
This option sets the default SCTP cookie authentication method, for
|
||||
when a method hasn't been explicitly selected via the
|
||||
net.sctp.cookie_hmac_alg sysctl.
|
||||
|
||||
config SCTP_DEFAULT_COOKIE_HMAC_MD5
|
||||
bool "Enable optional MD5 hmac cookie generation"
|
||||
help
|
||||
Enable optional MD5 hmac based SCTP cookie generation
|
||||
select SCTP_COOKIE_HMAC_MD5
|
||||
If unsure, choose the default (HMAC-SHA256).
|
||||
|
||||
config SCTP_DEFAULT_COOKIE_HMAC_SHA1
|
||||
bool "Enable optional SHA1 hmac cookie generation"
|
||||
help
|
||||
Enable optional SHA1 hmac based SCTP cookie generation
|
||||
select SCTP_COOKIE_HMAC_SHA1
|
||||
config SCTP_DEFAULT_COOKIE_HMAC_SHA256
|
||||
bool "HMAC-SHA256"
|
||||
|
||||
config SCTP_DEFAULT_COOKIE_HMAC_NONE
|
||||
bool "Use no hmac alg in SCTP cookie generation"
|
||||
help
|
||||
Use no hmac algorithm in SCTP cookie generation
|
||||
bool "None"
|
||||
|
||||
endchoice
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
config INET_SCTP_DIAG
|
||||
depends on INET_DIAG
|
||||
def_tristate 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 (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;
|
||||
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) +
|
||||
|
||||
@@ -35,6 +35,15 @@
|
||||
/* Forward declarations for internal helpers. */
|
||||
static void sctp_endpoint_bh_rcv(struct work_struct *work);
|
||||
|
||||
static void gen_cookie_auth_key(struct hmac_sha256_key *key)
|
||||
{
|
||||
u8 raw_key[SCTP_COOKIE_KEY_SIZE];
|
||||
|
||||
get_random_bytes(raw_key, sizeof(raw_key));
|
||||
hmac_sha256_preparekey(key, raw_key, sizeof(raw_key));
|
||||
memzero_explicit(raw_key, sizeof(raw_key));
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the base fields of the endpoint structure.
|
||||
*/
|
||||
@@ -45,10 +54,6 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
|
||||
struct net *net = sock_net(sk);
|
||||
struct sctp_shared_key *null_key;
|
||||
|
||||
ep->digest = kzalloc(SCTP_SIGNATURE_SIZE, gfp);
|
||||
if (!ep->digest)
|
||||
return NULL;
|
||||
|
||||
ep->asconf_enable = net->sctp.addip_enable;
|
||||
ep->auth_enable = net->sctp.auth_enable;
|
||||
if (ep->auth_enable) {
|
||||
@@ -90,8 +95,8 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
|
||||
/* Get the receive buffer policy for this endpoint */
|
||||
ep->rcvbuf_policy = net->sctp.rcvbuf_policy;
|
||||
|
||||
/* Initialize the secret key used with cookie. */
|
||||
get_random_bytes(ep->secret_key, sizeof(ep->secret_key));
|
||||
/* Generate the cookie authentication key. */
|
||||
gen_cookie_auth_key(&ep->cookie_auth_key);
|
||||
|
||||
/* SCTP-AUTH extensions*/
|
||||
INIT_LIST_HEAD(&ep->endpoint_shared_keys);
|
||||
@@ -118,7 +123,6 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
|
||||
nomem_shkey:
|
||||
sctp_auth_free(ep);
|
||||
nomem:
|
||||
kfree(ep->digest);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
@@ -205,9 +209,6 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Free the digest buffer */
|
||||
kfree(ep->digest);
|
||||
|
||||
/* SCTP-AUTH: Free up AUTH releated data such as shared keys
|
||||
* chunks and hmacs arrays that were allocated
|
||||
*/
|
||||
@@ -218,7 +219,7 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep)
|
||||
sctp_inq_free(&ep->base.inqueue);
|
||||
sctp_bind_addr_free(&ep->base.bind_addr);
|
||||
|
||||
memset(ep->secret_key, 0, sizeof(ep->secret_key));
|
||||
memzero_explicit(&ep->cookie_auth_key, sizeof(ep->cookie_auth_key));
|
||||
|
||||
sk = ep->base.sk;
|
||||
/* Remove and free the port */
|
||||
|
||||
@@ -1334,14 +1334,9 @@ static int __net_init sctp_defaults_init(struct net *net)
|
||||
/* Whether Cookie Preservative is enabled(1) or not(0) */
|
||||
net->sctp.cookie_preserve_enable = 1;
|
||||
|
||||
/* Default sctp sockets to use md5 as their hmac alg */
|
||||
#if defined (CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5)
|
||||
net->sctp.sctp_hmac_alg = "md5";
|
||||
#elif defined (CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1)
|
||||
net->sctp.sctp_hmac_alg = "sha1";
|
||||
#else
|
||||
net->sctp.sctp_hmac_alg = NULL;
|
||||
#endif
|
||||
/* Whether cookie authentication is enabled(1) or not(0) */
|
||||
net->sctp.cookie_auth_enable =
|
||||
!IS_ENABLED(CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE);
|
||||
|
||||
/* Max.Burst - 4 */
|
||||
net->sctp.max_burst = SCTP_DEFAULT_MAX_BURST;
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/utils.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ip.h>
|
||||
@@ -1319,7 +1319,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 */
|
||||
@@ -1674,8 +1674,10 @@ static struct sctp_cookie_param *sctp_pack_cookie(
|
||||
* out on the network.
|
||||
*/
|
||||
retval = kzalloc(*cookie_len, GFP_ATOMIC);
|
||||
if (!retval)
|
||||
goto nodata;
|
||||
if (!retval) {
|
||||
*cookie_len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cookie = (struct sctp_signed_cookie *) retval->body;
|
||||
|
||||
@@ -1706,26 +1708,14 @@ static struct sctp_cookie_param *sctp_pack_cookie(
|
||||
memcpy((__u8 *)(cookie + 1) +
|
||||
ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len);
|
||||
|
||||
if (sctp_sk(ep->base.sk)->hmac) {
|
||||
struct crypto_shash *tfm = sctp_sk(ep->base.sk)->hmac;
|
||||
int err;
|
||||
|
||||
/* Sign the message. */
|
||||
err = crypto_shash_setkey(tfm, ep->secret_key,
|
||||
sizeof(ep->secret_key)) ?:
|
||||
crypto_shash_tfm_digest(tfm, (u8 *)&cookie->c, bodysize,
|
||||
cookie->signature);
|
||||
if (err)
|
||||
goto free_cookie;
|
||||
/* Sign the cookie, if cookie authentication is enabled. */
|
||||
if (sctp_sk(ep->base.sk)->cookie_auth_enable) {
|
||||
static_assert(sizeof(cookie->mac) == SHA256_DIGEST_SIZE);
|
||||
hmac_sha256(&ep->cookie_auth_key, (const u8 *)&cookie->c,
|
||||
bodysize, cookie->mac);
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
||||
free_cookie:
|
||||
kfree(retval);
|
||||
nodata:
|
||||
*cookie_len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Unpack the cookie from COOKIE ECHO chunk, recreating the association. */
|
||||
@@ -1740,7 +1730,6 @@ struct sctp_association *sctp_unpack_cookie(
|
||||
struct sctp_signed_cookie *cookie;
|
||||
struct sk_buff *skb = chunk->skb;
|
||||
struct sctp_cookie *bear_cookie;
|
||||
__u8 *digest = ep->digest;
|
||||
enum sctp_scope scope;
|
||||
unsigned int len;
|
||||
ktime_t kt;
|
||||
@@ -1770,30 +1759,19 @@ struct sctp_association *sctp_unpack_cookie(
|
||||
cookie = chunk->subh.cookie_hdr;
|
||||
bear_cookie = &cookie->c;
|
||||
|
||||
if (!sctp_sk(ep->base.sk)->hmac)
|
||||
goto no_hmac;
|
||||
/* Verify the cookie's MAC, if cookie authentication is enabled. */
|
||||
if (sctp_sk(ep->base.sk)->cookie_auth_enable) {
|
||||
u8 mac[SHA256_DIGEST_SIZE];
|
||||
|
||||
/* Check the signature. */
|
||||
{
|
||||
struct crypto_shash *tfm = sctp_sk(ep->base.sk)->hmac;
|
||||
int err;
|
||||
|
||||
err = crypto_shash_setkey(tfm, ep->secret_key,
|
||||
sizeof(ep->secret_key)) ?:
|
||||
crypto_shash_tfm_digest(tfm, (u8 *)bear_cookie, bodysize,
|
||||
digest);
|
||||
if (err) {
|
||||
*error = -SCTP_IERROR_NOMEM;
|
||||
hmac_sha256(&ep->cookie_auth_key, (const u8 *)bear_cookie,
|
||||
bodysize, mac);
|
||||
static_assert(sizeof(cookie->mac) == sizeof(mac));
|
||||
if (crypto_memneq(mac, cookie->mac, sizeof(mac))) {
|
||||
*error = -SCTP_IERROR_BAD_SIG;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {
|
||||
*error = -SCTP_IERROR_BAD_SIG;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
no_hmac:
|
||||
/* IG Section 2.35.2:
|
||||
* 3) Compare the port numbers and the verification tag contained
|
||||
* within the COOKIE ECHO chunk to the actual port numbers and the
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <crypto/utils.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ip.h>
|
||||
@@ -4361,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;
|
||||
|
||||
@@ -4416,7 +4417,7 @@ static enum sctp_ierror sctp_sf_authenticate(
|
||||
sh_key, GFP_ATOMIC);
|
||||
|
||||
/* Discard the packet if the digests do not match */
|
||||
if (memcmp(save_digest, digest, sig_len)) {
|
||||
if (crypto_memneq(save_digest, digest, sig_len)) {
|
||||
kfree(save_digest);
|
||||
return SCTP_IERROR_BAD_SIG;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <crypto/hash.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/wait.h>
|
||||
@@ -4987,7 +4986,7 @@ static int sctp_init_sock(struct sock *sk)
|
||||
sp->default_rcv_context = 0;
|
||||
sp->max_burst = net->sctp.max_burst;
|
||||
|
||||
sp->sctp_hmac_alg = net->sctp.sctp_hmac_alg;
|
||||
sp->cookie_auth_enable = net->sctp.cookie_auth_enable;
|
||||
|
||||
/* Initialize default setup parameters. These parameters
|
||||
* can be modified with the SCTP_INITMSG socket option or
|
||||
@@ -5079,8 +5078,6 @@ static int sctp_init_sock(struct sock *sk)
|
||||
if (!sp->ep)
|
||||
return -ENOMEM;
|
||||
|
||||
sp->hmac = NULL;
|
||||
|
||||
sk->sk_destruct = sctp_destruct_sock;
|
||||
|
||||
SCTP_DBG_OBJCNT_INC(sock);
|
||||
@@ -5117,18 +5114,8 @@ static void sctp_destroy_sock(struct sock *sk)
|
||||
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
|
||||
}
|
||||
|
||||
/* Triggered when there are no references on the socket anymore */
|
||||
static void sctp_destruct_common(struct sock *sk)
|
||||
{
|
||||
struct sctp_sock *sp = sctp_sk(sk);
|
||||
|
||||
/* Free up the HMAC transform. */
|
||||
crypto_free_shash(sp->hmac);
|
||||
}
|
||||
|
||||
static void sctp_destruct_sock(struct sock *sk)
|
||||
{
|
||||
sctp_destruct_common(sk);
|
||||
inet_sock_destruct(sk);
|
||||
}
|
||||
|
||||
@@ -8530,22 +8517,8 @@ static int sctp_listen_start(struct sock *sk, int backlog)
|
||||
{
|
||||
struct sctp_sock *sp = sctp_sk(sk);
|
||||
struct sctp_endpoint *ep = sp->ep;
|
||||
struct crypto_shash *tfm = NULL;
|
||||
char alg[32];
|
||||
int err;
|
||||
|
||||
/* Allocate HMAC for generating cookie. */
|
||||
if (!sp->hmac && sp->sctp_hmac_alg) {
|
||||
sprintf(alg, "hmac(%s)", sp->sctp_hmac_alg);
|
||||
tfm = crypto_alloc_shash(alg, 0, 0);
|
||||
if (IS_ERR(tfm)) {
|
||||
net_info_ratelimited("failed to load transform for %s: %ld\n",
|
||||
sp->sctp_hmac_alg, PTR_ERR(tfm));
|
||||
return -ENOSYS;
|
||||
}
|
||||
sctp_sk(sk)->hmac = tfm;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a bind() or sctp_bindx() is not called prior to a listen()
|
||||
* call that allows new associations to be accepted, the system
|
||||
@@ -9561,7 +9534,6 @@ static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
|
||||
* copy.
|
||||
*/
|
||||
newsp->ep = newep;
|
||||
newsp->hmac = NULL;
|
||||
|
||||
/* Hook this new socket in to the bind_hash list. */
|
||||
head = &sctp_port_hashtable[sctp_phashfn(sock_net(oldsk),
|
||||
@@ -9581,16 +9553,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
|
||||
@@ -9723,7 +9685,6 @@ struct proto sctp_prot = {
|
||||
|
||||
static void sctp_v6_destruct_sock(struct sock *sk)
|
||||
{
|
||||
sctp_destruct_common(sk);
|
||||
inet6_sock_destruct(sk);
|
||||
}
|
||||
|
||||
|
||||
@@ -174,7 +174,7 @@ static struct ctl_table sctp_net_table[] = {
|
||||
},
|
||||
{
|
||||
.procname = "cookie_hmac_alg",
|
||||
.data = &init_net.sctp.sctp_hmac_alg,
|
||||
.data = &init_net.sctp.cookie_auth_enable,
|
||||
.maxlen = 8,
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_sctp_do_hmac_alg,
|
||||
@@ -388,10 +388,8 @@ static int proc_sctp_do_hmac_alg(const struct ctl_table *ctl, int write,
|
||||
void *buffer, size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
struct net *net = container_of(ctl->data, struct net,
|
||||
sctp.sctp_hmac_alg);
|
||||
sctp.cookie_auth_enable);
|
||||
struct ctl_table tbl;
|
||||
bool changed = false;
|
||||
char *none = "none";
|
||||
char tmp[8] = {0};
|
||||
int ret;
|
||||
|
||||
@@ -399,35 +397,26 @@ static int proc_sctp_do_hmac_alg(const struct ctl_table *ctl, int write,
|
||||
|
||||
if (write) {
|
||||
tbl.data = tmp;
|
||||
tbl.maxlen = sizeof(tmp);
|
||||
} else {
|
||||
tbl.data = net->sctp.sctp_hmac_alg ? : none;
|
||||
tbl.maxlen = strlen(tbl.data);
|
||||
tbl.maxlen = sizeof(tmp) - 1;
|
||||
ret = proc_dostring(&tbl, 1, buffer, lenp, ppos);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!strcmp(tmp, "sha256")) {
|
||||
net->sctp.cookie_auth_enable = 1;
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(tmp, "none")) {
|
||||
net->sctp.cookie_auth_enable = 0;
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = proc_dostring(&tbl, write, buffer, lenp, ppos);
|
||||
if (write && ret == 0) {
|
||||
#ifdef CONFIG_CRYPTO_MD5
|
||||
if (!strncmp(tmp, "md5", 3)) {
|
||||
net->sctp.sctp_hmac_alg = "md5";
|
||||
changed = true;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_CRYPTO_SHA1
|
||||
if (!strncmp(tmp, "sha1", 4)) {
|
||||
net->sctp.sctp_hmac_alg = "sha1";
|
||||
changed = true;
|
||||
}
|
||||
#endif
|
||||
if (!strncmp(tmp, "none", 4)) {
|
||||
net->sctp.sctp_hmac_alg = NULL;
|
||||
changed = true;
|
||||
}
|
||||
if (!changed)
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
if (net->sctp.cookie_auth_enable)
|
||||
tbl.data = (char *)"sha256";
|
||||
else
|
||||
tbl.data = (char *)"none";
|
||||
tbl.maxlen = strlen(tbl.data);
|
||||
return proc_dostring(&tbl, 0, buffer, lenp, ppos);
|
||||
}
|
||||
|
||||
static int proc_sctp_do_rto_min(const struct ctl_table *ctl, int write,
|
||||
|
||||
@@ -26,6 +26,7 @@ CONFIG_IFB=y
|
||||
CONFIG_INET_DIAG=y
|
||||
CONFIG_INET_ESP=y
|
||||
CONFIG_INET_ESP_OFFLOAD=y
|
||||
CONFIG_CRYPTO_SHA1=y
|
||||
CONFIG_NET_FOU=y
|
||||
CONFIG_NET_FOU_IP_TUNNELS=y
|
||||
CONFIG_NETFILTER=y
|
||||
|
||||
@@ -13,6 +13,7 @@ CONFIG_BRIDGE_VLAN_FILTERING=y
|
||||
CONFIG_CGROUP_BPF=y
|
||||
CONFIG_DUMMY=m
|
||||
CONFIG_INET_ESP=m
|
||||
CONFIG_CRYPTO_SHA1=m
|
||||
CONFIG_IP_NF_MATCH_RPFILTER=m
|
||||
CONFIG_IP6_NF_MATCH_RPFILTER=m
|
||||
CONFIG_IP_NF_IPTABLES=m
|
||||
|
||||
Reference in New Issue
Block a user