aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2008-01-28 22:37:29 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-31 22:27:03 -0500
commit1a6509d991225ad210de54c63314fd9542922095 (patch)
treeafe5c560388558bebd3e21b7c6f789a28a323a51
parent6fbf2cb77461a0cd0675228d20dd0f70d7b2251f (diff)
[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>
-rw-r--r--include/linux/pfkeyv2.h6
-rw-r--r--include/linux/xfrm.h8
-rw-r--r--include/net/xfrm.h8
-rw-r--r--net/ipv4/esp4.c71
-rw-r--r--net/ipv6/esp6.c77
-rw-r--r--net/xfrm/xfrm_algo.c138
-rw-r--r--net/xfrm/xfrm_user.c71
7 files changed, 347 insertions, 32 deletions
diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h
index d9db5f62ee48..6db69ff5d83e 100644
--- a/include/linux/pfkeyv2.h
+++ b/include/linux/pfkeyv2.h
@@ -298,6 +298,12 @@ struct sadb_x_sec_ctx {
298#define SADB_X_EALG_BLOWFISHCBC 7 298#define SADB_X_EALG_BLOWFISHCBC 7
299#define SADB_EALG_NULL 11 299#define SADB_EALG_NULL 11
300#define SADB_X_EALG_AESCBC 12 300#define SADB_X_EALG_AESCBC 12
301#define SADB_X_EALG_AES_CCM_ICV8 14
302#define SADB_X_EALG_AES_CCM_ICV12 15
303#define SADB_X_EALG_AES_CCM_ICV16 16
304#define SADB_X_EALG_AES_GCM_ICV8 18
305#define SADB_X_EALG_AES_GCM_ICV12 19
306#define SADB_X_EALG_AES_GCM_ICV16 20
301#define SADB_X_EALG_CAMELLIACBC 22 307#define SADB_X_EALG_CAMELLIACBC 22
302#define SADB_EALG_MAX 253 /* last EALG */ 308#define SADB_EALG_MAX 253 /* last EALG */
303/* private allocations should use 249-255 (RFC2407) */ 309/* private allocations should use 249-255 (RFC2407) */
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 9b5b00c4ef9d..e31b8c84f2c9 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -96,6 +96,13 @@ struct xfrm_algo {
96 char alg_key[0]; 96 char alg_key[0];
97}; 97};
98 98
99struct xfrm_algo_aead {
100 char alg_name[64];
101 int alg_key_len; /* in bits */
102 int alg_icv_len; /* in bits */
103 char alg_key[0];
104};
105
99struct xfrm_stats { 106struct xfrm_stats {
100 __u32 replay_window; 107 __u32 replay_window;
101 __u32 replay; 108 __u32 replay;
@@ -270,6 +277,7 @@ enum xfrm_attr_type_t {
270 XFRMA_LASTUSED, 277 XFRMA_LASTUSED,
271 XFRMA_POLICY_TYPE, /* struct xfrm_userpolicy_type */ 278 XFRMA_POLICY_TYPE, /* struct xfrm_userpolicy_type */
272 XFRMA_MIGRATE, 279 XFRMA_MIGRATE,
280 XFRMA_ALG_AEAD, /* struct xfrm_algo_aead */
273 __XFRMA_MAX 281 __XFRMA_MAX
274 282
275#define XFRMA_MAX (__XFRMA_MAX - 1) 283#define XFRMA_MAX (__XFRMA_MAX - 1)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 5ebb9ba479b1..34d373775a0e 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -159,6 +159,7 @@ struct xfrm_state
159 struct xfrm_algo *aalg; 159 struct xfrm_algo *aalg;
160 struct xfrm_algo *ealg; 160 struct xfrm_algo *ealg;
161 struct xfrm_algo *calg; 161 struct xfrm_algo *calg;
162 struct xfrm_algo_aead *aead;
162 163
163 /* Data for encapsulator */ 164 /* Data for encapsulator */
164 struct xfrm_encap_tmpl *encap; 165 struct xfrm_encap_tmpl *encap;
@@ -1108,6 +1109,10 @@ static inline int xfrm_id_proto_match(u8 proto, u8 userproto)
1108/* 1109/*
1109 * xfrm algorithm information 1110 * xfrm algorithm information
1110 */ 1111 */
1112struct xfrm_algo_aead_info {
1113 u16 icv_truncbits;
1114};
1115
1111struct xfrm_algo_auth_info { 1116struct xfrm_algo_auth_info {
1112 u16 icv_truncbits; 1117 u16 icv_truncbits;
1113 u16 icv_fullbits; 1118 u16 icv_fullbits;
@@ -1127,6 +1132,7 @@ struct xfrm_algo_desc {
1127 char *compat; 1132 char *compat;
1128 u8 available:1; 1133 u8 available:1;
1129 union { 1134 union {
1135 struct xfrm_algo_aead_info aead;
1130 struct xfrm_algo_auth_info auth; 1136 struct xfrm_algo_auth_info auth;
1131 struct xfrm_algo_encr_info encr; 1137 struct xfrm_algo_encr_info encr;
1132 struct xfrm_algo_comp_info comp; 1138 struct xfrm_algo_comp_info comp;
@@ -1343,6 +1349,8 @@ extern struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id);
1343extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe); 1349extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe);
1344extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe); 1350extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe);
1345extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe); 1351extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe);
1352extern struct xfrm_algo_desc *xfrm_aead_get_byname(char *name, int icv_len,
1353 int probe);
1346 1354
1347struct hash_desc; 1355struct hash_desc;
1348struct scatterlist; 1356struct scatterlist;
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index c4047223bfbe..fac4f102c9f9 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -439,32 +439,53 @@ static void esp_destroy(struct xfrm_state *x)
439 kfree(esp); 439 kfree(esp);
440} 440}
441 441
442static int esp_init_state(struct xfrm_state *x) 442static int esp_init_aead(struct xfrm_state *x)
443{ 443{
444 struct esp_data *esp = NULL; 444 struct esp_data *esp = x->data;
445 struct crypto_aead *aead;
446 int err;
447
448 aead = crypto_alloc_aead(x->aead->alg_name, 0, 0);
449 err = PTR_ERR(aead);
450 if (IS_ERR(aead))
451 goto error;
452
453 esp->aead = aead;
454
455 err = crypto_aead_setkey(aead, x->aead->alg_key,
456 (x->aead->alg_key_len + 7) / 8);
457 if (err)
458 goto error;
459
460 err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
461 if (err)
462 goto error;
463
464error:
465 return err;
466}
467
468static int esp_init_authenc(struct xfrm_state *x)
469{
470 struct esp_data *esp = x->data;
445 struct crypto_aead *aead; 471 struct crypto_aead *aead;
446 struct crypto_authenc_key_param *param; 472 struct crypto_authenc_key_param *param;
447 struct rtattr *rta; 473 struct rtattr *rta;
448 char *key; 474 char *key;
449 char *p; 475 char *p;
450 char authenc_name[CRYPTO_MAX_ALG_NAME]; 476 char authenc_name[CRYPTO_MAX_ALG_NAME];
451 u32 align;
452 unsigned int keylen; 477 unsigned int keylen;
453 int err; 478 int err;
454 479
480 err = -EINVAL;
455 if (x->ealg == NULL) 481 if (x->ealg == NULL)
456 return -EINVAL; 482 goto error;
457 483
484 err = -ENAMETOOLONG;
458 if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)", 485 if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
459 x->aalg ? x->aalg->alg_name : "digest_null", 486 x->aalg ? x->aalg->alg_name : "digest_null",
460 x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME) 487 x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
461 return -ENAMETOOLONG; 488 goto error;
462
463 esp = kzalloc(sizeof(*esp), GFP_KERNEL);
464 if (esp == NULL)
465 return -ENOMEM;
466
467 x->data = esp;
468 489
469 aead = crypto_alloc_aead(authenc_name, 0, 0); 490 aead = crypto_alloc_aead(authenc_name, 0, 0);
470 err = PTR_ERR(aead); 491 err = PTR_ERR(aead);
@@ -512,8 +533,6 @@ static int esp_init_state(struct xfrm_state *x)
512 goto free_key; 533 goto free_key;
513 } 534 }
514 535
515 esp->padlen = 0;
516
517 param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8); 536 param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
518 memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8); 537 memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
519 538
@@ -522,9 +541,35 @@ static int esp_init_state(struct xfrm_state *x)
522free_key: 541free_key:
523 kfree(key); 542 kfree(key);
524 543
544error:
545 return err;
546}
547
548static int esp_init_state(struct xfrm_state *x)
549{
550 struct esp_data *esp;
551 struct crypto_aead *aead;
552 u32 align;
553 int err;
554
555 esp = kzalloc(sizeof(*esp), GFP_KERNEL);
556 if (esp == NULL)
557 return -ENOMEM;
558
559 x->data = esp;
560
561 if (x->aead)
562 err = esp_init_aead(x);
563 else
564 err = esp_init_authenc(x);
565
525 if (err) 566 if (err)
526 goto error; 567 goto error;
527 568
569 aead = esp->aead;
570
571 esp->padlen = 0;
572
528 x->props.header_len = sizeof(struct ip_esp_hdr) + 573 x->props.header_len = sizeof(struct ip_esp_hdr) +
529 crypto_aead_ivsize(aead); 574 crypto_aead_ivsize(aead);
530 if (x->props.mode == XFRM_MODE_TUNNEL) 575 if (x->props.mode == XFRM_MODE_TUNNEL)
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index dc821acf3d33..ca48c56c4b17 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -382,35 +382,53 @@ static void esp6_destroy(struct xfrm_state *x)
382 kfree(esp); 382 kfree(esp);
383} 383}
384 384
385static int esp6_init_state(struct xfrm_state *x) 385static int esp_init_aead(struct xfrm_state *x)
386{
387 struct esp_data *esp = x->data;
388 struct crypto_aead *aead;
389 int err;
390
391 aead = crypto_alloc_aead(x->aead->alg_name, 0, 0);
392 err = PTR_ERR(aead);
393 if (IS_ERR(aead))
394 goto error;
395
396 esp->aead = aead;
397
398 err = crypto_aead_setkey(aead, x->aead->alg_key,
399 (x->aead->alg_key_len + 7) / 8);
400 if (err)
401 goto error;
402
403 err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
404 if (err)
405 goto error;
406
407error:
408 return err;
409}
410
411static int esp_init_authenc(struct xfrm_state *x)
386{ 412{
387 struct esp_data *esp = NULL; 413 struct esp_data *esp = x->data;
388 struct crypto_aead *aead; 414 struct crypto_aead *aead;
389 struct crypto_authenc_key_param *param; 415 struct crypto_authenc_key_param *param;
390 struct rtattr *rta; 416 struct rtattr *rta;
391 char *key; 417 char *key;
392 char *p; 418 char *p;
393 char authenc_name[CRYPTO_MAX_ALG_NAME]; 419 char authenc_name[CRYPTO_MAX_ALG_NAME];
394 u32 align;
395 unsigned int keylen; 420 unsigned int keylen;
396 int err; 421 int err;
397 422
423 err = -EINVAL;
398 if (x->ealg == NULL) 424 if (x->ealg == NULL)
399 return -EINVAL; 425 goto error;
400
401 if (x->encap)
402 return -EINVAL;
403 426
427 err = -ENAMETOOLONG;
404 if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)", 428 if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)",
405 x->aalg ? x->aalg->alg_name : "digest_null", 429 x->aalg ? x->aalg->alg_name : "digest_null",
406 x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME) 430 x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
407 return -ENAMETOOLONG; 431 goto error;
408
409 esp = kzalloc(sizeof(*esp), GFP_KERNEL);
410 if (esp == NULL)
411 return -ENOMEM;
412
413 x->data = esp;
414 432
415 aead = crypto_alloc_aead(authenc_name, 0, 0); 433 aead = crypto_alloc_aead(authenc_name, 0, 0);
416 err = PTR_ERR(aead); 434 err = PTR_ERR(aead);
@@ -458,8 +476,6 @@ static int esp6_init_state(struct xfrm_state *x)
458 goto free_key; 476 goto free_key;
459 } 477 }
460 478
461 esp->padlen = 0;
462
463 param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8); 479 param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
464 memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8); 480 memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
465 481
@@ -468,9 +484,38 @@ static int esp6_init_state(struct xfrm_state *x)
468free_key: 484free_key:
469 kfree(key); 485 kfree(key);
470 486
487error:
488 return err;
489}
490
491static int esp6_init_state(struct xfrm_state *x)
492{
493 struct esp_data *esp;
494 struct crypto_aead *aead;
495 u32 align;
496 int err;
497
498 if (x->encap)
499 return -EINVAL;
500
501 esp = kzalloc(sizeof(*esp), GFP_KERNEL);
502 if (esp == NULL)
503 return -ENOMEM;
504
505 x->data = esp;
506
507 if (x->aead)
508 err = esp_init_aead(x);
509 else
510 err = esp_init_authenc(x);
511
471 if (err) 512 if (err)
472 goto error; 513 goto error;
473 514
515 aead = esp->aead;
516
517 esp->padlen = 0;
518
474 x->props.header_len = sizeof(struct ip_esp_hdr) + 519 x->props.header_len = sizeof(struct ip_esp_hdr) +
475 crypto_aead_ivsize(aead); 520 crypto_aead_ivsize(aead);
476 switch (x->props.mode) { 521 switch (x->props.mode) {
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index 02e3ecf9585d..6cc15250de69 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -28,6 +28,105 @@
28 * that instantiated crypto transforms have correct parameters for IPsec 28 * that instantiated crypto transforms have correct parameters for IPsec
29 * purposes. 29 * purposes.
30 */ 30 */
31static struct xfrm_algo_desc aead_list[] = {
32{
33 .name = "rfc4106(gcm(aes))",
34
35 .uinfo = {
36 .aead = {
37 .icv_truncbits = 64,
38 }
39 },
40
41 .desc = {
42 .sadb_alg_id = SADB_X_EALG_AES_GCM_ICV8,
43 .sadb_alg_ivlen = 8,
44 .sadb_alg_minbits = 128,
45 .sadb_alg_maxbits = 256
46 }
47},
48{
49 .name = "rfc4106(gcm(aes))",
50
51 .uinfo = {
52 .aead = {
53 .icv_truncbits = 96,
54 }
55 },
56
57 .desc = {
58 .sadb_alg_id = SADB_X_EALG_AES_GCM_ICV12,
59 .sadb_alg_ivlen = 8,
60 .sadb_alg_minbits = 128,
61 .sadb_alg_maxbits = 256
62 }
63},
64{
65 .name = "rfc4106(gcm(aes))",
66
67 .uinfo = {
68 .aead = {
69 .icv_truncbits = 128,
70 }
71 },
72
73 .desc = {
74 .sadb_alg_id = SADB_X_EALG_AES_GCM_ICV16,
75 .sadb_alg_ivlen = 8,
76 .sadb_alg_minbits = 128,
77 .sadb_alg_maxbits = 256
78 }
79},
80{
81 .name = "rfc4309(ccm(aes))",
82
83 .uinfo = {
84 .aead = {
85 .icv_truncbits = 64,
86 }
87 },
88
89 .desc = {
90 .sadb_alg_id = SADB_X_EALG_AES_CCM_ICV8,
91 .sadb_alg_ivlen = 8,
92 .sadb_alg_minbits = 128,
93 .sadb_alg_maxbits = 256
94 }
95},
96{
97 .name = "rfc4309(ccm(aes))",
98
99 .uinfo = {
100 .aead = {
101 .icv_truncbits = 96,
102 }
103 },
104
105 .desc = {
106 .sadb_alg_id = SADB_X_EALG_AES_CCM_ICV12,
107 .sadb_alg_ivlen = 8,
108 .sadb_alg_minbits = 128,
109 .sadb_alg_maxbits = 256
110 }
111},
112{
113 .name = "rfc4309(ccm(aes))",
114
115 .uinfo = {
116 .aead = {
117 .icv_truncbits = 128,
118 }
119 },
120
121 .desc = {
122 .sadb_alg_id = SADB_X_EALG_AES_CCM_ICV16,
123 .sadb_alg_ivlen = 8,
124 .sadb_alg_minbits = 128,
125 .sadb_alg_maxbits = 256
126 }
127},
128};
129
31static struct xfrm_algo_desc aalg_list[] = { 130static struct xfrm_algo_desc aalg_list[] = {
32{ 131{
33 .name = "hmac(digest_null)", 132 .name = "hmac(digest_null)",
@@ -332,6 +431,11 @@ static struct xfrm_algo_desc calg_list[] = {
332}, 431},
333}; 432};
334 433
434static inline int aead_entries(void)
435{
436 return ARRAY_SIZE(aead_list);
437}
438
335static inline int aalg_entries(void) 439static inline int aalg_entries(void)
336{ 440{
337 return ARRAY_SIZE(aalg_list); 441 return ARRAY_SIZE(aalg_list);
@@ -354,6 +458,13 @@ struct xfrm_algo_list {
354 u32 mask; 458 u32 mask;
355}; 459};
356 460
461static const struct xfrm_algo_list xfrm_aead_list = {
462 .algs = aead_list,
463 .entries = ARRAY_SIZE(aead_list),
464 .type = CRYPTO_ALG_TYPE_AEAD,
465 .mask = CRYPTO_ALG_TYPE_MASK,
466};
467
357static const struct xfrm_algo_list xfrm_aalg_list = { 468static const struct xfrm_algo_list xfrm_aalg_list = {
358 .algs = aalg_list, 469 .algs = aalg_list,
359 .entries = ARRAY_SIZE(aalg_list), 470 .entries = ARRAY_SIZE(aalg_list),
@@ -461,6 +572,33 @@ struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe)
461} 572}
462EXPORT_SYMBOL_GPL(xfrm_calg_get_byname); 573EXPORT_SYMBOL_GPL(xfrm_calg_get_byname);
463 574
575struct xfrm_aead_name {
576 const char *name;
577 int icvbits;
578};
579
580static int xfrm_aead_name_match(const struct xfrm_algo_desc *entry,
581 const void *data)
582{
583 const struct xfrm_aead_name *aead = data;
584 const char *name = aead->name;
585
586 return aead->icvbits == entry->uinfo.aead.icv_truncbits && name &&
587 !strcmp(name, entry->name);
588}
589
590struct xfrm_algo_desc *xfrm_aead_get_byname(char *name, int icv_len, int probe)
591{
592 struct xfrm_aead_name data = {
593 .name = name,
594 .icvbits = icv_len,
595 };
596
597 return xfrm_find_algo(&xfrm_aead_list, xfrm_aead_name_match, &data,
598 probe);
599}
600EXPORT_SYMBOL_GPL(xfrm_aead_get_byname);
601
464struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx) 602struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx)
465{ 603{
466 if (idx >= aalg_entries()) 604 if (idx >= aalg_entries())
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index e0ccdf267813..78338079b7f5 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -31,6 +31,11 @@
31#include <linux/in6.h> 31#include <linux/in6.h>
32#endif 32#endif
33 33
34static inline int aead_len(struct xfrm_algo_aead *alg)
35{
36 return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
37}
38
34static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) 39static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
35{ 40{
36 struct nlattr *rt = attrs[type]; 41 struct nlattr *rt = attrs[type];
@@ -68,6 +73,22 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
68 return 0; 73 return 0;
69} 74}
70 75
76static int verify_aead(struct nlattr **attrs)
77{
78 struct nlattr *rt = attrs[XFRMA_ALG_AEAD];
79 struct xfrm_algo_aead *algp;
80
81 if (!rt)
82 return 0;
83
84 algp = nla_data(rt);
85 if (nla_len(rt) < aead_len(algp))
86 return -EINVAL;
87
88 algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0';
89 return 0;
90}
91
71static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type, 92static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type,
72 xfrm_address_t **addrp) 93 xfrm_address_t **addrp)
73{ 94{
@@ -119,20 +140,28 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
119 switch (p->id.proto) { 140 switch (p->id.proto) {
120 case IPPROTO_AH: 141 case IPPROTO_AH:
121 if (!attrs[XFRMA_ALG_AUTH] || 142 if (!attrs[XFRMA_ALG_AUTH] ||
143 attrs[XFRMA_ALG_AEAD] ||
122 attrs[XFRMA_ALG_CRYPT] || 144 attrs[XFRMA_ALG_CRYPT] ||
123 attrs[XFRMA_ALG_COMP]) 145 attrs[XFRMA_ALG_COMP])
124 goto out; 146 goto out;
125 break; 147 break;
126 148
127 case IPPROTO_ESP: 149 case IPPROTO_ESP:
128 if ((!attrs[XFRMA_ALG_AUTH] && 150 if (attrs[XFRMA_ALG_COMP])
129 !attrs[XFRMA_ALG_CRYPT]) || 151 goto out;
130 attrs[XFRMA_ALG_COMP]) 152 if (!attrs[XFRMA_ALG_AUTH] &&
153 !attrs[XFRMA_ALG_CRYPT] &&
154 !attrs[XFRMA_ALG_AEAD])
155 goto out;
156 if ((attrs[XFRMA_ALG_AUTH] ||
157 attrs[XFRMA_ALG_CRYPT]) &&
158 attrs[XFRMA_ALG_AEAD])
131 goto out; 159 goto out;
132 break; 160 break;
133 161
134 case IPPROTO_COMP: 162 case IPPROTO_COMP:
135 if (!attrs[XFRMA_ALG_COMP] || 163 if (!attrs[XFRMA_ALG_COMP] ||
164 attrs[XFRMA_ALG_AEAD] ||
136 attrs[XFRMA_ALG_AUTH] || 165 attrs[XFRMA_ALG_AUTH] ||
137 attrs[XFRMA_ALG_CRYPT]) 166 attrs[XFRMA_ALG_CRYPT])
138 goto out; 167 goto out;
@@ -143,6 +172,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
143 case IPPROTO_ROUTING: 172 case IPPROTO_ROUTING:
144 if (attrs[XFRMA_ALG_COMP] || 173 if (attrs[XFRMA_ALG_COMP] ||
145 attrs[XFRMA_ALG_AUTH] || 174 attrs[XFRMA_ALG_AUTH] ||
175 attrs[XFRMA_ALG_AEAD] ||
146 attrs[XFRMA_ALG_CRYPT] || 176 attrs[XFRMA_ALG_CRYPT] ||
147 attrs[XFRMA_ENCAP] || 177 attrs[XFRMA_ENCAP] ||
148 attrs[XFRMA_SEC_CTX] || 178 attrs[XFRMA_SEC_CTX] ||
@@ -155,6 +185,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
155 goto out; 185 goto out;
156 } 186 }
157 187
188 if ((err = verify_aead(attrs)))
189 goto out;
158 if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH))) 190 if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH)))
159 goto out; 191 goto out;
160 if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT))) 192 if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT)))
@@ -208,6 +240,31 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
208 return 0; 240 return 0;
209} 241}
210 242
243static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props,
244 struct nlattr *rta)
245{
246 struct xfrm_algo_aead *p, *ualg;
247 struct xfrm_algo_desc *algo;
248
249 if (!rta)
250 return 0;
251
252 ualg = nla_data(rta);
253
254 algo = xfrm_aead_get_byname(ualg->alg_name, ualg->alg_icv_len, 1);
255 if (!algo)
256 return -ENOSYS;
257 *props = algo->desc.sadb_alg_id;
258
259 p = kmemdup(ualg, aead_len(ualg), GFP_KERNEL);
260 if (!p)
261 return -ENOMEM;
262
263 strcpy(p->alg_name, algo->name);
264 *algpp = p;
265 return 0;
266}
267
211static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx) 268static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx)
212{ 269{
213 int len = 0; 270 int len = 0;
@@ -286,6 +343,9 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p,
286 343
287 copy_from_user_state(x, p); 344 copy_from_user_state(x, p);
288 345
346 if ((err = attach_aead(&x->aead, &x->props.ealgo,
347 attrs[XFRMA_ALG_AEAD])))
348 goto error;
289 if ((err = attach_one_algo(&x->aalg, &x->props.aalgo, 349 if ((err = attach_one_algo(&x->aalg, &x->props.aalgo,
290 xfrm_aalg_get_byname, 350 xfrm_aalg_get_byname,
291 attrs[XFRMA_ALG_AUTH]))) 351 attrs[XFRMA_ALG_AUTH])))
@@ -510,6 +570,8 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
510 if (x->lastused) 570 if (x->lastused)
511 NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused); 571 NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused);
512 572
573 if (x->aead)
574 NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead);
513 if (x->aalg) 575 if (x->aalg)
514 NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg); 576 NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg);
515 if (x->ealg) 577 if (x->ealg)
@@ -1808,6 +1870,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
1808#undef XMSGSIZE 1870#undef XMSGSIZE
1809 1871
1810static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { 1872static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
1873 [XFRMA_ALG_AEAD] = { .len = sizeof(struct xfrm_algo_aead) },
1811 [XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) }, 1874 [XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) },
1812 [XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) }, 1875 [XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) },
1813 [XFRMA_ALG_COMP] = { .len = sizeof(struct xfrm_algo) }, 1876 [XFRMA_ALG_COMP] = { .len = sizeof(struct xfrm_algo) },
@@ -1972,6 +2035,8 @@ static int xfrm_notify_sa_flush(struct km_event *c)
1972static inline size_t xfrm_sa_len(struct xfrm_state *x) 2035static inline size_t xfrm_sa_len(struct xfrm_state *x)
1973{ 2036{
1974 size_t l = 0; 2037 size_t l = 0;
2038 if (x->aead)
2039 l += nla_total_size(aead_len(x->aead));
1975 if (x->aalg) 2040 if (x->aalg)
1976 l += nla_total_size(xfrm_alg_len(x->aalg)); 2041 l += nla_total_size(xfrm_alg_len(x->aalg));
1977 if (x->ealg) 2042 if (x->ealg)