[IPSEC]: Add support for combined mode algorithms
This patch adds support for combined mode algorithms with GCM being the first algorithm supported. Combined mode algorithms can be added through the xfrm_user interface using the new algorithm payload type XFRMA_ALG_AEAD. Each algorithms is identified by its name and the ICV length. For the purposes of matching algorithms in xfrm_tmpl structures, combined mode algorithms occupy the same name space as encryption algorithms. This is in line with how they are negotiated using IKE. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
6fbf2cb774
Коммит
1a6509d991
|
@ -298,6 +298,12 @@ struct sadb_x_sec_ctx {
|
||||||
#define SADB_X_EALG_BLOWFISHCBC 7
|
#define SADB_X_EALG_BLOWFISHCBC 7
|
||||||
#define SADB_EALG_NULL 11
|
#define SADB_EALG_NULL 11
|
||||||
#define SADB_X_EALG_AESCBC 12
|
#define SADB_X_EALG_AESCBC 12
|
||||||
|
#define SADB_X_EALG_AES_CCM_ICV8 14
|
||||||
|
#define SADB_X_EALG_AES_CCM_ICV12 15
|
||||||
|
#define SADB_X_EALG_AES_CCM_ICV16 16
|
||||||
|
#define SADB_X_EALG_AES_GCM_ICV8 18
|
||||||
|
#define SADB_X_EALG_AES_GCM_ICV12 19
|
||||||
|
#define SADB_X_EALG_AES_GCM_ICV16 20
|
||||||
#define SADB_X_EALG_CAMELLIACBC 22
|
#define SADB_X_EALG_CAMELLIACBC 22
|
||||||
#define SADB_EALG_MAX 253 /* last EALG */
|
#define SADB_EALG_MAX 253 /* last EALG */
|
||||||
/* private allocations should use 249-255 (RFC2407) */
|
/* private allocations should use 249-255 (RFC2407) */
|
||||||
|
|
|
@ -96,6 +96,13 @@ struct xfrm_algo {
|
||||||
char alg_key[0];
|
char alg_key[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct xfrm_algo_aead {
|
||||||
|
char alg_name[64];
|
||||||
|
int alg_key_len; /* in bits */
|
||||||
|
int alg_icv_len; /* in bits */
|
||||||
|
char alg_key[0];
|
||||||
|
};
|
||||||
|
|
||||||
struct xfrm_stats {
|
struct xfrm_stats {
|
||||||
__u32 replay_window;
|
__u32 replay_window;
|
||||||
__u32 replay;
|
__u32 replay;
|
||||||
|
@ -270,6 +277,7 @@ enum xfrm_attr_type_t {
|
||||||
XFRMA_LASTUSED,
|
XFRMA_LASTUSED,
|
||||||
XFRMA_POLICY_TYPE, /* struct xfrm_userpolicy_type */
|
XFRMA_POLICY_TYPE, /* struct xfrm_userpolicy_type */
|
||||||
XFRMA_MIGRATE,
|
XFRMA_MIGRATE,
|
||||||
|
XFRMA_ALG_AEAD, /* struct xfrm_algo_aead */
|
||||||
__XFRMA_MAX
|
__XFRMA_MAX
|
||||||
|
|
||||||
#define XFRMA_MAX (__XFRMA_MAX - 1)
|
#define XFRMA_MAX (__XFRMA_MAX - 1)
|
||||||
|
|
|
@ -159,6 +159,7 @@ struct xfrm_state
|
||||||
struct xfrm_algo *aalg;
|
struct xfrm_algo *aalg;
|
||||||
struct xfrm_algo *ealg;
|
struct xfrm_algo *ealg;
|
||||||
struct xfrm_algo *calg;
|
struct xfrm_algo *calg;
|
||||||
|
struct xfrm_algo_aead *aead;
|
||||||
|
|
||||||
/* Data for encapsulator */
|
/* Data for encapsulator */
|
||||||
struct xfrm_encap_tmpl *encap;
|
struct xfrm_encap_tmpl *encap;
|
||||||
|
@ -1108,6 +1109,10 @@ static inline int xfrm_id_proto_match(u8 proto, u8 userproto)
|
||||||
/*
|
/*
|
||||||
* xfrm algorithm information
|
* xfrm algorithm information
|
||||||
*/
|
*/
|
||||||
|
struct xfrm_algo_aead_info {
|
||||||
|
u16 icv_truncbits;
|
||||||
|
};
|
||||||
|
|
||||||
struct xfrm_algo_auth_info {
|
struct xfrm_algo_auth_info {
|
||||||
u16 icv_truncbits;
|
u16 icv_truncbits;
|
||||||
u16 icv_fullbits;
|
u16 icv_fullbits;
|
||||||
|
@ -1127,6 +1132,7 @@ struct xfrm_algo_desc {
|
||||||
char *compat;
|
char *compat;
|
||||||
u8 available:1;
|
u8 available:1;
|
||||||
union {
|
union {
|
||||||
|
struct xfrm_algo_aead_info aead;
|
||||||
struct xfrm_algo_auth_info auth;
|
struct xfrm_algo_auth_info auth;
|
||||||
struct xfrm_algo_encr_info encr;
|
struct xfrm_algo_encr_info encr;
|
||||||
struct xfrm_algo_comp_info comp;
|
struct xfrm_algo_comp_info comp;
|
||||||
|
@ -1343,6 +1349,8 @@ extern struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id);
|
||||||
extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe);
|
extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe);
|
||||||
extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe);
|
extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe);
|
||||||
extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe);
|
extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe);
|
||||||
|
extern struct xfrm_algo_desc *xfrm_aead_get_byname(char *name, int icv_len,
|
||||||
|
int probe);
|
||||||
|
|
||||||
struct hash_desc;
|
struct hash_desc;
|
||||||
struct scatterlist;
|
struct scatterlist;
|
||||||
|
|
|
@ -439,32 +439,53 @@ static void esp_destroy(struct xfrm_state *x)
|
||||||
kfree(esp);
|
kfree(esp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int esp_init_state(struct xfrm_state *x)
|
static int esp_init_aead(struct xfrm_state *x)
|
||||||
{
|
{
|
||||||
struct esp_data *esp = NULL;
|
struct esp_data *esp = x->data;
|
||||||
|
struct crypto_aead *aead;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
aead = crypto_alloc_aead(x->aead->alg_name, 0, 0);
|
||||||
|
err = PTR_ERR(aead);
|
||||||
|
if (IS_ERR(aead))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
esp->aead = aead;
|
||||||
|
|
||||||
|
err = crypto_aead_setkey(aead, x->aead->alg_key,
|
||||||
|
(x->aead->alg_key_len + 7) / 8);
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int esp_init_authenc(struct xfrm_state *x)
|
||||||
|
{
|
||||||
|
struct esp_data *esp = x->data;
|
||||||
struct crypto_aead *aead;
|
struct crypto_aead *aead;
|
||||||
struct crypto_authenc_key_param *param;
|
struct crypto_authenc_key_param *param;
|
||||||
struct rtattr *rta;
|
struct rtattr *rta;
|
||||||
char *key;
|
char *key;
|
||||||
char *p;
|
char *p;
|
||||||
char authenc_name[CRYPTO_MAX_ALG_NAME];
|
char authenc_name[CRYPTO_MAX_ALG_NAME];
|
||||||
u32 align;
|
|
||||||
unsigned int keylen;
|
unsigned int keylen;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
err = -EINVAL;
|
||||||
if (x->ealg == NULL)
|
if (x->ealg == NULL)
|
||||||
return -EINVAL;
|
goto error;
|
||||||
|
|
||||||
|
err = -ENAMETOOLONG;
|
||||||
if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
|
if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
|
||||||
x->aalg ? x->aalg->alg_name : "digest_null",
|
x->aalg ? x->aalg->alg_name : "digest_null",
|
||||||
x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
|
x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
|
||||||
return -ENAMETOOLONG;
|
goto error;
|
||||||
|
|
||||||
esp = kzalloc(sizeof(*esp), GFP_KERNEL);
|
|
||||||
if (esp == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
x->data = esp;
|
|
||||||
|
|
||||||
aead = crypto_alloc_aead(authenc_name, 0, 0);
|
aead = crypto_alloc_aead(authenc_name, 0, 0);
|
||||||
err = PTR_ERR(aead);
|
err = PTR_ERR(aead);
|
||||||
|
@ -512,8 +533,6 @@ static int esp_init_state(struct xfrm_state *x)
|
||||||
goto free_key;
|
goto free_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp->padlen = 0;
|
|
||||||
|
|
||||||
param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
|
param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
|
||||||
memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
|
memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
|
||||||
|
|
||||||
|
@ -522,9 +541,35 @@ static int esp_init_state(struct xfrm_state *x)
|
||||||
free_key:
|
free_key:
|
||||||
kfree(key);
|
kfree(key);
|
||||||
|
|
||||||
|
error:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int esp_init_state(struct xfrm_state *x)
|
||||||
|
{
|
||||||
|
struct esp_data *esp;
|
||||||
|
struct crypto_aead *aead;
|
||||||
|
u32 align;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
esp = kzalloc(sizeof(*esp), GFP_KERNEL);
|
||||||
|
if (esp == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
x->data = esp;
|
||||||
|
|
||||||
|
if (x->aead)
|
||||||
|
err = esp_init_aead(x);
|
||||||
|
else
|
||||||
|
err = esp_init_authenc(x);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
aead = esp->aead;
|
||||||
|
|
||||||
|
esp->padlen = 0;
|
||||||
|
|
||||||
x->props.header_len = sizeof(struct ip_esp_hdr) +
|
x->props.header_len = sizeof(struct ip_esp_hdr) +
|
||||||
crypto_aead_ivsize(aead);
|
crypto_aead_ivsize(aead);
|
||||||
if (x->props.mode == XFRM_MODE_TUNNEL)
|
if (x->props.mode == XFRM_MODE_TUNNEL)
|
||||||
|
|
|
@ -382,35 +382,53 @@ static void esp6_destroy(struct xfrm_state *x)
|
||||||
kfree(esp);
|
kfree(esp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int esp6_init_state(struct xfrm_state *x)
|
static int esp_init_aead(struct xfrm_state *x)
|
||||||
{
|
{
|
||||||
struct esp_data *esp = NULL;
|
struct esp_data *esp = x->data;
|
||||||
|
struct crypto_aead *aead;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
aead = crypto_alloc_aead(x->aead->alg_name, 0, 0);
|
||||||
|
err = PTR_ERR(aead);
|
||||||
|
if (IS_ERR(aead))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
esp->aead = aead;
|
||||||
|
|
||||||
|
err = crypto_aead_setkey(aead, x->aead->alg_key,
|
||||||
|
(x->aead->alg_key_len + 7) / 8);
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int esp_init_authenc(struct xfrm_state *x)
|
||||||
|
{
|
||||||
|
struct esp_data *esp = x->data;
|
||||||
struct crypto_aead *aead;
|
struct crypto_aead *aead;
|
||||||
struct crypto_authenc_key_param *param;
|
struct crypto_authenc_key_param *param;
|
||||||
struct rtattr *rta;
|
struct rtattr *rta;
|
||||||
char *key;
|
char *key;
|
||||||
char *p;
|
char *p;
|
||||||
char authenc_name[CRYPTO_MAX_ALG_NAME];
|
char authenc_name[CRYPTO_MAX_ALG_NAME];
|
||||||
u32 align;
|
|
||||||
unsigned int keylen;
|
unsigned int keylen;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
err = -EINVAL;
|
||||||
if (x->ealg == NULL)
|
if (x->ealg == NULL)
|
||||||
return -EINVAL;
|
goto error;
|
||||||
|
|
||||||
if (x->encap)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
|
err = -ENAMETOOLONG;
|
||||||
if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
|
if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
|
||||||
x->aalg ? x->aalg->alg_name : "digest_null",
|
x->aalg ? x->aalg->alg_name : "digest_null",
|
||||||
x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
|
x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
|
||||||
return -ENAMETOOLONG;
|
goto error;
|
||||||
|
|
||||||
esp = kzalloc(sizeof(*esp), GFP_KERNEL);
|
|
||||||
if (esp == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
x->data = esp;
|
|
||||||
|
|
||||||
aead = crypto_alloc_aead(authenc_name, 0, 0);
|
aead = crypto_alloc_aead(authenc_name, 0, 0);
|
||||||
err = PTR_ERR(aead);
|
err = PTR_ERR(aead);
|
||||||
|
@ -458,8 +476,6 @@ static int esp6_init_state(struct xfrm_state *x)
|
||||||
goto free_key;
|
goto free_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp->padlen = 0;
|
|
||||||
|
|
||||||
param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
|
param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
|
||||||
memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
|
memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
|
||||||
|
|
||||||
|
@ -468,9 +484,38 @@ static int esp6_init_state(struct xfrm_state *x)
|
||||||
free_key:
|
free_key:
|
||||||
kfree(key);
|
kfree(key);
|
||||||
|
|
||||||
|
error:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int esp6_init_state(struct xfrm_state *x)
|
||||||
|
{
|
||||||
|
struct esp_data *esp;
|
||||||
|
struct crypto_aead *aead;
|
||||||
|
u32 align;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (x->encap)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
esp = kzalloc(sizeof(*esp), GFP_KERNEL);
|
||||||
|
if (esp == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
x->data = esp;
|
||||||
|
|
||||||
|
if (x->aead)
|
||||||
|
err = esp_init_aead(x);
|
||||||
|
else
|
||||||
|
err = esp_init_authenc(x);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
aead = esp->aead;
|
||||||
|
|
||||||
|
esp->padlen = 0;
|
||||||
|
|
||||||
x->props.header_len = sizeof(struct ip_esp_hdr) +
|
x->props.header_len = sizeof(struct ip_esp_hdr) +
|
||||||
crypto_aead_ivsize(aead);
|
crypto_aead_ivsize(aead);
|
||||||
switch (x->props.mode) {
|
switch (x->props.mode) {
|
||||||
|
|
|
@ -28,6 +28,105 @@
|
||||||
* that instantiated crypto transforms have correct parameters for IPsec
|
* that instantiated crypto transforms have correct parameters for IPsec
|
||||||
* purposes.
|
* purposes.
|
||||||
*/
|
*/
|
||||||
|
static struct xfrm_algo_desc aead_list[] = {
|
||||||
|
{
|
||||||
|
.name = "rfc4106(gcm(aes))",
|
||||||
|
|
||||||
|
.uinfo = {
|
||||||
|
.aead = {
|
||||||
|
.icv_truncbits = 64,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
.desc = {
|
||||||
|
.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV8,
|
||||||
|
.sadb_alg_ivlen = 8,
|
||||||
|
.sadb_alg_minbits = 128,
|
||||||
|
.sadb_alg_maxbits = 256
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "rfc4106(gcm(aes))",
|
||||||
|
|
||||||
|
.uinfo = {
|
||||||
|
.aead = {
|
||||||
|
.icv_truncbits = 96,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
.desc = {
|
||||||
|
.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV12,
|
||||||
|
.sadb_alg_ivlen = 8,
|
||||||
|
.sadb_alg_minbits = 128,
|
||||||
|
.sadb_alg_maxbits = 256
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "rfc4106(gcm(aes))",
|
||||||
|
|
||||||
|
.uinfo = {
|
||||||
|
.aead = {
|
||||||
|
.icv_truncbits = 128,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
.desc = {
|
||||||
|
.sadb_alg_id = SADB_X_EALG_AES_GCM_ICV16,
|
||||||
|
.sadb_alg_ivlen = 8,
|
||||||
|
.sadb_alg_minbits = 128,
|
||||||
|
.sadb_alg_maxbits = 256
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "rfc4309(ccm(aes))",
|
||||||
|
|
||||||
|
.uinfo = {
|
||||||
|
.aead = {
|
||||||
|
.icv_truncbits = 64,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
.desc = {
|
||||||
|
.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV8,
|
||||||
|
.sadb_alg_ivlen = 8,
|
||||||
|
.sadb_alg_minbits = 128,
|
||||||
|
.sadb_alg_maxbits = 256
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "rfc4309(ccm(aes))",
|
||||||
|
|
||||||
|
.uinfo = {
|
||||||
|
.aead = {
|
||||||
|
.icv_truncbits = 96,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
.desc = {
|
||||||
|
.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV12,
|
||||||
|
.sadb_alg_ivlen = 8,
|
||||||
|
.sadb_alg_minbits = 128,
|
||||||
|
.sadb_alg_maxbits = 256
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "rfc4309(ccm(aes))",
|
||||||
|
|
||||||
|
.uinfo = {
|
||||||
|
.aead = {
|
||||||
|
.icv_truncbits = 128,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
.desc = {
|
||||||
|
.sadb_alg_id = SADB_X_EALG_AES_CCM_ICV16,
|
||||||
|
.sadb_alg_ivlen = 8,
|
||||||
|
.sadb_alg_minbits = 128,
|
||||||
|
.sadb_alg_maxbits = 256
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static struct xfrm_algo_desc aalg_list[] = {
|
static struct xfrm_algo_desc aalg_list[] = {
|
||||||
{
|
{
|
||||||
.name = "hmac(digest_null)",
|
.name = "hmac(digest_null)",
|
||||||
|
@ -332,6 +431,11 @@ static struct xfrm_algo_desc calg_list[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline int aead_entries(void)
|
||||||
|
{
|
||||||
|
return ARRAY_SIZE(aead_list);
|
||||||
|
}
|
||||||
|
|
||||||
static inline int aalg_entries(void)
|
static inline int aalg_entries(void)
|
||||||
{
|
{
|
||||||
return ARRAY_SIZE(aalg_list);
|
return ARRAY_SIZE(aalg_list);
|
||||||
|
@ -354,6 +458,13 @@ struct xfrm_algo_list {
|
||||||
u32 mask;
|
u32 mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct xfrm_algo_list xfrm_aead_list = {
|
||||||
|
.algs = aead_list,
|
||||||
|
.entries = ARRAY_SIZE(aead_list),
|
||||||
|
.type = CRYPTO_ALG_TYPE_AEAD,
|
||||||
|
.mask = CRYPTO_ALG_TYPE_MASK,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct xfrm_algo_list xfrm_aalg_list = {
|
static const struct xfrm_algo_list xfrm_aalg_list = {
|
||||||
.algs = aalg_list,
|
.algs = aalg_list,
|
||||||
.entries = ARRAY_SIZE(aalg_list),
|
.entries = ARRAY_SIZE(aalg_list),
|
||||||
|
@ -461,6 +572,33 @@ struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xfrm_calg_get_byname);
|
EXPORT_SYMBOL_GPL(xfrm_calg_get_byname);
|
||||||
|
|
||||||
|
struct xfrm_aead_name {
|
||||||
|
const char *name;
|
||||||
|
int icvbits;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int xfrm_aead_name_match(const struct xfrm_algo_desc *entry,
|
||||||
|
const void *data)
|
||||||
|
{
|
||||||
|
const struct xfrm_aead_name *aead = data;
|
||||||
|
const char *name = aead->name;
|
||||||
|
|
||||||
|
return aead->icvbits == entry->uinfo.aead.icv_truncbits && name &&
|
||||||
|
!strcmp(name, entry->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct xfrm_algo_desc *xfrm_aead_get_byname(char *name, int icv_len, int probe)
|
||||||
|
{
|
||||||
|
struct xfrm_aead_name data = {
|
||||||
|
.name = name,
|
||||||
|
.icvbits = icv_len,
|
||||||
|
};
|
||||||
|
|
||||||
|
return xfrm_find_algo(&xfrm_aead_list, xfrm_aead_name_match, &data,
|
||||||
|
probe);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(xfrm_aead_get_byname);
|
||||||
|
|
||||||
struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx)
|
struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx)
|
||||||
{
|
{
|
||||||
if (idx >= aalg_entries())
|
if (idx >= aalg_entries())
|
||||||
|
|
|
@ -31,6 +31,11 @@
|
||||||
#include <linux/in6.h>
|
#include <linux/in6.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline int aead_len(struct xfrm_algo_aead *alg)
|
||||||
|
{
|
||||||
|
return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
|
||||||
|
}
|
||||||
|
|
||||||
static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
|
static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
|
||||||
{
|
{
|
||||||
struct nlattr *rt = attrs[type];
|
struct nlattr *rt = attrs[type];
|
||||||
|
@ -68,6 +73,22 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int verify_aead(struct nlattr **attrs)
|
||||||
|
{
|
||||||
|
struct nlattr *rt = attrs[XFRMA_ALG_AEAD];
|
||||||
|
struct xfrm_algo_aead *algp;
|
||||||
|
|
||||||
|
if (!rt)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
algp = nla_data(rt);
|
||||||
|
if (nla_len(rt) < aead_len(algp))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type,
|
static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type,
|
||||||
xfrm_address_t **addrp)
|
xfrm_address_t **addrp)
|
||||||
{
|
{
|
||||||
|
@ -119,20 +140,28 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
|
||||||
switch (p->id.proto) {
|
switch (p->id.proto) {
|
||||||
case IPPROTO_AH:
|
case IPPROTO_AH:
|
||||||
if (!attrs[XFRMA_ALG_AUTH] ||
|
if (!attrs[XFRMA_ALG_AUTH] ||
|
||||||
|
attrs[XFRMA_ALG_AEAD] ||
|
||||||
attrs[XFRMA_ALG_CRYPT] ||
|
attrs[XFRMA_ALG_CRYPT] ||
|
||||||
attrs[XFRMA_ALG_COMP])
|
attrs[XFRMA_ALG_COMP])
|
||||||
goto out;
|
goto out;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IPPROTO_ESP:
|
case IPPROTO_ESP:
|
||||||
if ((!attrs[XFRMA_ALG_AUTH] &&
|
if (attrs[XFRMA_ALG_COMP])
|
||||||
!attrs[XFRMA_ALG_CRYPT]) ||
|
goto out;
|
||||||
attrs[XFRMA_ALG_COMP])
|
if (!attrs[XFRMA_ALG_AUTH] &&
|
||||||
|
!attrs[XFRMA_ALG_CRYPT] &&
|
||||||
|
!attrs[XFRMA_ALG_AEAD])
|
||||||
|
goto out;
|
||||||
|
if ((attrs[XFRMA_ALG_AUTH] ||
|
||||||
|
attrs[XFRMA_ALG_CRYPT]) &&
|
||||||
|
attrs[XFRMA_ALG_AEAD])
|
||||||
goto out;
|
goto out;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IPPROTO_COMP:
|
case IPPROTO_COMP:
|
||||||
if (!attrs[XFRMA_ALG_COMP] ||
|
if (!attrs[XFRMA_ALG_COMP] ||
|
||||||
|
attrs[XFRMA_ALG_AEAD] ||
|
||||||
attrs[XFRMA_ALG_AUTH] ||
|
attrs[XFRMA_ALG_AUTH] ||
|
||||||
attrs[XFRMA_ALG_CRYPT])
|
attrs[XFRMA_ALG_CRYPT])
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -143,6 +172,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
|
||||||
case IPPROTO_ROUTING:
|
case IPPROTO_ROUTING:
|
||||||
if (attrs[XFRMA_ALG_COMP] ||
|
if (attrs[XFRMA_ALG_COMP] ||
|
||||||
attrs[XFRMA_ALG_AUTH] ||
|
attrs[XFRMA_ALG_AUTH] ||
|
||||||
|
attrs[XFRMA_ALG_AEAD] ||
|
||||||
attrs[XFRMA_ALG_CRYPT] ||
|
attrs[XFRMA_ALG_CRYPT] ||
|
||||||
attrs[XFRMA_ENCAP] ||
|
attrs[XFRMA_ENCAP] ||
|
||||||
attrs[XFRMA_SEC_CTX] ||
|
attrs[XFRMA_SEC_CTX] ||
|
||||||
|
@ -155,6 +185,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((err = verify_aead(attrs)))
|
||||||
|
goto out;
|
||||||
if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH)))
|
if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH)))
|
||||||
goto out;
|
goto out;
|
||||||
if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT)))
|
if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT)))
|
||||||
|
@ -208,6 +240,31 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props,
|
||||||
|
struct nlattr *rta)
|
||||||
|
{
|
||||||
|
struct xfrm_algo_aead *p, *ualg;
|
||||||
|
struct xfrm_algo_desc *algo;
|
||||||
|
|
||||||
|
if (!rta)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ualg = nla_data(rta);
|
||||||
|
|
||||||
|
algo = xfrm_aead_get_byname(ualg->alg_name, ualg->alg_icv_len, 1);
|
||||||
|
if (!algo)
|
||||||
|
return -ENOSYS;
|
||||||
|
*props = algo->desc.sadb_alg_id;
|
||||||
|
|
||||||
|
p = kmemdup(ualg, aead_len(ualg), GFP_KERNEL);
|
||||||
|
if (!p)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
strcpy(p->alg_name, algo->name);
|
||||||
|
*algpp = p;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx)
|
static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx)
|
||||||
{
|
{
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
@ -286,6 +343,9 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p,
|
||||||
|
|
||||||
copy_from_user_state(x, p);
|
copy_from_user_state(x, p);
|
||||||
|
|
||||||
|
if ((err = attach_aead(&x->aead, &x->props.ealgo,
|
||||||
|
attrs[XFRMA_ALG_AEAD])))
|
||||||
|
goto error;
|
||||||
if ((err = attach_one_algo(&x->aalg, &x->props.aalgo,
|
if ((err = attach_one_algo(&x->aalg, &x->props.aalgo,
|
||||||
xfrm_aalg_get_byname,
|
xfrm_aalg_get_byname,
|
||||||
attrs[XFRMA_ALG_AUTH])))
|
attrs[XFRMA_ALG_AUTH])))
|
||||||
|
@ -510,6 +570,8 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
|
||||||
if (x->lastused)
|
if (x->lastused)
|
||||||
NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused);
|
NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused);
|
||||||
|
|
||||||
|
if (x->aead)
|
||||||
|
NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead);
|
||||||
if (x->aalg)
|
if (x->aalg)
|
||||||
NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg);
|
NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg);
|
||||||
if (x->ealg)
|
if (x->ealg)
|
||||||
|
@ -1808,6 +1870,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
|
||||||
#undef XMSGSIZE
|
#undef XMSGSIZE
|
||||||
|
|
||||||
static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
|
static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
|
||||||
|
[XFRMA_ALG_AEAD] = { .len = sizeof(struct xfrm_algo_aead) },
|
||||||
[XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) },
|
[XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) },
|
||||||
[XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) },
|
[XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) },
|
||||||
[XFRMA_ALG_COMP] = { .len = sizeof(struct xfrm_algo) },
|
[XFRMA_ALG_COMP] = { .len = sizeof(struct xfrm_algo) },
|
||||||
|
@ -1972,6 +2035,8 @@ static int xfrm_notify_sa_flush(struct km_event *c)
|
||||||
static inline size_t xfrm_sa_len(struct xfrm_state *x)
|
static inline size_t xfrm_sa_len(struct xfrm_state *x)
|
||||||
{
|
{
|
||||||
size_t l = 0;
|
size_t l = 0;
|
||||||
|
if (x->aead)
|
||||||
|
l += nla_total_size(aead_len(x->aead));
|
||||||
if (x->aalg)
|
if (x->aalg)
|
||||||
l += nla_total_size(xfrm_alg_len(x->aalg));
|
l += nla_total_size(xfrm_alg_len(x->aalg));
|
||||||
if (x->ealg)
|
if (x->ealg)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче