diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2008-01-28 22:37:29 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-31 22:27:03 -0500 |
commit | 1a6509d991225ad210de54c63314fd9542922095 (patch) | |
tree | afe5c560388558bebd3e21b7c6f789a28a323a51 | |
parent | 6fbf2cb77461a0cd0675228d20dd0f70d7b2251f (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.h | 6 | ||||
-rw-r--r-- | include/linux/xfrm.h | 8 | ||||
-rw-r--r-- | include/net/xfrm.h | 8 | ||||
-rw-r--r-- | net/ipv4/esp4.c | 71 | ||||
-rw-r--r-- | net/ipv6/esp6.c | 77 | ||||
-rw-r--r-- | net/xfrm/xfrm_algo.c | 138 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 71 |
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 | ||
99 | struct 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 | |||
99 | struct xfrm_stats { | 106 | struct 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 | */ |
1112 | struct xfrm_algo_aead_info { | ||
1113 | u16 icv_truncbits; | ||
1114 | }; | ||
1115 | |||
1111 | struct xfrm_algo_auth_info { | 1116 | struct 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); | |||
1343 | extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe); | 1349 | extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe); |
1344 | extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe); | 1350 | extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe); |
1345 | extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe); | 1351 | extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe); |
1352 | extern struct xfrm_algo_desc *xfrm_aead_get_byname(char *name, int icv_len, | ||
1353 | int probe); | ||
1346 | 1354 | ||
1347 | struct hash_desc; | 1355 | struct hash_desc; |
1348 | struct scatterlist; | 1356 | struct 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 | ||
442 | static int esp_init_state(struct xfrm_state *x) | 442 | static 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 | |||
464 | error: | ||
465 | return err; | ||
466 | } | ||
467 | |||
468 | static 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) | |||
522 | free_key: | 541 | free_key: |
523 | kfree(key); | 542 | kfree(key); |
524 | 543 | ||
544 | error: | ||
545 | return err; | ||
546 | } | ||
547 | |||
548 | static 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 | ||
385 | static int esp6_init_state(struct xfrm_state *x) | 385 | static 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 | |||
407 | error: | ||
408 | return err; | ||
409 | } | ||
410 | |||
411 | static 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) | |||
468 | free_key: | 484 | free_key: |
469 | kfree(key); | 485 | kfree(key); |
470 | 486 | ||
487 | error: | ||
488 | return err; | ||
489 | } | ||
490 | |||
491 | static 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 | */ |
31 | static 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 | |||
31 | static struct xfrm_algo_desc aalg_list[] = { | 130 | static 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 | ||
434 | static inline int aead_entries(void) | ||
435 | { | ||
436 | return ARRAY_SIZE(aead_list); | ||
437 | } | ||
438 | |||
335 | static inline int aalg_entries(void) | 439 | static 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 | ||
461 | static 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 | |||
357 | static const struct xfrm_algo_list xfrm_aalg_list = { | 468 | static 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 | } |
462 | EXPORT_SYMBOL_GPL(xfrm_calg_get_byname); | 573 | EXPORT_SYMBOL_GPL(xfrm_calg_get_byname); |
463 | 574 | ||
575 | struct xfrm_aead_name { | ||
576 | const char *name; | ||
577 | int icvbits; | ||
578 | }; | ||
579 | |||
580 | static 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 | |||
590 | struct 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 | } | ||
600 | EXPORT_SYMBOL_GPL(xfrm_aead_get_byname); | ||
601 | |||
464 | struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx) | 602 | struct 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 | ||
34 | static inline int aead_len(struct xfrm_algo_aead *alg) | ||
35 | { | ||
36 | return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); | ||
37 | } | ||
38 | |||
34 | static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) | 39 | static 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 | ||
76 | static 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 | |||
71 | static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type, | 92 | static 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 | ||
243 | static 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 | |||
211 | static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx) | 268 | static 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 | ||
1810 | static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { | 1872 | static 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) | |||
1972 | static inline size_t xfrm_sa_len(struct xfrm_state *x) | 2035 | static 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) |