diff options
author | Eric Biggers <ebiggers@google.com> | 2018-01-03 14:16:29 -0500 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2018-01-12 07:03:39 -0500 |
commit | f8d33fac84806eebd2ba31a3136066eeca19255f (patch) | |
tree | ca1ff03d50c7f17a3a1ae173f1324af826068619 /crypto | |
parent | 4e1d14bcd10a33537918a9a747ab90fc5c2e6d7f (diff) |
crypto: skcipher - prevent using skciphers without setting key
Similar to what was done for the hash API, update the skcipher API to
track whether each transform has been keyed, and reject
encryption/decryption if a key is needed but one hasn't been set.
This isn't as important as the equivalent fix for the hash API because
symmetric ciphers almost always require a key (the "null cipher" is the
only exception), so are unlikely to be used without one. Still,
tracking the key will prevent accidental unkeyed use. algif_skcipher
also had to track the key anyway, so the new flag replaces that and
simplifies the algif_skcipher implementation.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/algif_skcipher.c | 59 | ||||
-rw-r--r-- | crypto/skcipher.c | 30 |
2 files changed, 39 insertions, 50 deletions
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index c5c47b680152..c88e5e4cd6a6 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c | |||
@@ -38,11 +38,6 @@ | |||
38 | #include <linux/net.h> | 38 | #include <linux/net.h> |
39 | #include <net/sock.h> | 39 | #include <net/sock.h> |
40 | 40 | ||
41 | struct skcipher_tfm { | ||
42 | struct crypto_skcipher *skcipher; | ||
43 | bool has_key; | ||
44 | }; | ||
45 | |||
46 | static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg, | 41 | static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg, |
47 | size_t size) | 42 | size_t size) |
48 | { | 43 | { |
@@ -50,8 +45,7 @@ static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg, | |||
50 | struct alg_sock *ask = alg_sk(sk); | 45 | struct alg_sock *ask = alg_sk(sk); |
51 | struct sock *psk = ask->parent; | 46 | struct sock *psk = ask->parent; |
52 | struct alg_sock *pask = alg_sk(psk); | 47 | struct alg_sock *pask = alg_sk(psk); |
53 | struct skcipher_tfm *skc = pask->private; | 48 | struct crypto_skcipher *tfm = pask->private; |
54 | struct crypto_skcipher *tfm = skc->skcipher; | ||
55 | unsigned ivsize = crypto_skcipher_ivsize(tfm); | 49 | unsigned ivsize = crypto_skcipher_ivsize(tfm); |
56 | 50 | ||
57 | return af_alg_sendmsg(sock, msg, size, ivsize); | 51 | return af_alg_sendmsg(sock, msg, size, ivsize); |
@@ -65,8 +59,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, | |||
65 | struct sock *psk = ask->parent; | 59 | struct sock *psk = ask->parent; |
66 | struct alg_sock *pask = alg_sk(psk); | 60 | struct alg_sock *pask = alg_sk(psk); |
67 | struct af_alg_ctx *ctx = ask->private; | 61 | struct af_alg_ctx *ctx = ask->private; |
68 | struct skcipher_tfm *skc = pask->private; | 62 | struct crypto_skcipher *tfm = pask->private; |
69 | struct crypto_skcipher *tfm = skc->skcipher; | ||
70 | unsigned int bs = crypto_skcipher_blocksize(tfm); | 63 | unsigned int bs = crypto_skcipher_blocksize(tfm); |
71 | struct af_alg_async_req *areq; | 64 | struct af_alg_async_req *areq; |
72 | int err = 0; | 65 | int err = 0; |
@@ -221,7 +214,7 @@ static int skcipher_check_key(struct socket *sock) | |||
221 | int err = 0; | 214 | int err = 0; |
222 | struct sock *psk; | 215 | struct sock *psk; |
223 | struct alg_sock *pask; | 216 | struct alg_sock *pask; |
224 | struct skcipher_tfm *tfm; | 217 | struct crypto_skcipher *tfm; |
225 | struct sock *sk = sock->sk; | 218 | struct sock *sk = sock->sk; |
226 | struct alg_sock *ask = alg_sk(sk); | 219 | struct alg_sock *ask = alg_sk(sk); |
227 | 220 | ||
@@ -235,7 +228,7 @@ static int skcipher_check_key(struct socket *sock) | |||
235 | 228 | ||
236 | err = -ENOKEY; | 229 | err = -ENOKEY; |
237 | lock_sock_nested(psk, SINGLE_DEPTH_NESTING); | 230 | lock_sock_nested(psk, SINGLE_DEPTH_NESTING); |
238 | if (!tfm->has_key) | 231 | if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) |
239 | goto unlock; | 232 | goto unlock; |
240 | 233 | ||
241 | if (!pask->refcnt++) | 234 | if (!pask->refcnt++) |
@@ -314,41 +307,17 @@ static struct proto_ops algif_skcipher_ops_nokey = { | |||
314 | 307 | ||
315 | static void *skcipher_bind(const char *name, u32 type, u32 mask) | 308 | static void *skcipher_bind(const char *name, u32 type, u32 mask) |
316 | { | 309 | { |
317 | struct skcipher_tfm *tfm; | 310 | return crypto_alloc_skcipher(name, type, mask); |
318 | struct crypto_skcipher *skcipher; | ||
319 | |||
320 | tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); | ||
321 | if (!tfm) | ||
322 | return ERR_PTR(-ENOMEM); | ||
323 | |||
324 | skcipher = crypto_alloc_skcipher(name, type, mask); | ||
325 | if (IS_ERR(skcipher)) { | ||
326 | kfree(tfm); | ||
327 | return ERR_CAST(skcipher); | ||
328 | } | ||
329 | |||
330 | tfm->skcipher = skcipher; | ||
331 | |||
332 | return tfm; | ||
333 | } | 311 | } |
334 | 312 | ||
335 | static void skcipher_release(void *private) | 313 | static void skcipher_release(void *private) |
336 | { | 314 | { |
337 | struct skcipher_tfm *tfm = private; | 315 | crypto_free_skcipher(private); |
338 | |||
339 | crypto_free_skcipher(tfm->skcipher); | ||
340 | kfree(tfm); | ||
341 | } | 316 | } |
342 | 317 | ||
343 | static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen) | 318 | static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen) |
344 | { | 319 | { |
345 | struct skcipher_tfm *tfm = private; | 320 | return crypto_skcipher_setkey(private, key, keylen); |
346 | int err; | ||
347 | |||
348 | err = crypto_skcipher_setkey(tfm->skcipher, key, keylen); | ||
349 | tfm->has_key = !err; | ||
350 | |||
351 | return err; | ||
352 | } | 321 | } |
353 | 322 | ||
354 | static void skcipher_sock_destruct(struct sock *sk) | 323 | static void skcipher_sock_destruct(struct sock *sk) |
@@ -357,8 +326,7 @@ static void skcipher_sock_destruct(struct sock *sk) | |||
357 | struct af_alg_ctx *ctx = ask->private; | 326 | struct af_alg_ctx *ctx = ask->private; |
358 | struct sock *psk = ask->parent; | 327 | struct sock *psk = ask->parent; |
359 | struct alg_sock *pask = alg_sk(psk); | 328 | struct alg_sock *pask = alg_sk(psk); |
360 | struct skcipher_tfm *skc = pask->private; | 329 | struct crypto_skcipher *tfm = pask->private; |
361 | struct crypto_skcipher *tfm = skc->skcipher; | ||
362 | 330 | ||
363 | af_alg_pull_tsgl(sk, ctx->used, NULL, 0); | 331 | af_alg_pull_tsgl(sk, ctx->used, NULL, 0); |
364 | sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); | 332 | sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); |
@@ -370,22 +338,21 @@ static int skcipher_accept_parent_nokey(void *private, struct sock *sk) | |||
370 | { | 338 | { |
371 | struct af_alg_ctx *ctx; | 339 | struct af_alg_ctx *ctx; |
372 | struct alg_sock *ask = alg_sk(sk); | 340 | struct alg_sock *ask = alg_sk(sk); |
373 | struct skcipher_tfm *tfm = private; | 341 | struct crypto_skcipher *tfm = private; |
374 | struct crypto_skcipher *skcipher = tfm->skcipher; | ||
375 | unsigned int len = sizeof(*ctx); | 342 | unsigned int len = sizeof(*ctx); |
376 | 343 | ||
377 | ctx = sock_kmalloc(sk, len, GFP_KERNEL); | 344 | ctx = sock_kmalloc(sk, len, GFP_KERNEL); |
378 | if (!ctx) | 345 | if (!ctx) |
379 | return -ENOMEM; | 346 | return -ENOMEM; |
380 | 347 | ||
381 | ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(skcipher), | 348 | ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(tfm), |
382 | GFP_KERNEL); | 349 | GFP_KERNEL); |
383 | if (!ctx->iv) { | 350 | if (!ctx->iv) { |
384 | sock_kfree_s(sk, ctx, len); | 351 | sock_kfree_s(sk, ctx, len); |
385 | return -ENOMEM; | 352 | return -ENOMEM; |
386 | } | 353 | } |
387 | 354 | ||
388 | memset(ctx->iv, 0, crypto_skcipher_ivsize(skcipher)); | 355 | memset(ctx->iv, 0, crypto_skcipher_ivsize(tfm)); |
389 | 356 | ||
390 | INIT_LIST_HEAD(&ctx->tsgl_list); | 357 | INIT_LIST_HEAD(&ctx->tsgl_list); |
391 | ctx->len = len; | 358 | ctx->len = len; |
@@ -405,9 +372,9 @@ static int skcipher_accept_parent_nokey(void *private, struct sock *sk) | |||
405 | 372 | ||
406 | static int skcipher_accept_parent(void *private, struct sock *sk) | 373 | static int skcipher_accept_parent(void *private, struct sock *sk) |
407 | { | 374 | { |
408 | struct skcipher_tfm *tfm = private; | 375 | struct crypto_skcipher *tfm = private; |
409 | 376 | ||
410 | if (!tfm->has_key && crypto_skcipher_has_setkey(tfm->skcipher)) | 377 | if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) |
411 | return -ENOKEY; | 378 | return -ENOKEY; |
412 | 379 | ||
413 | return skcipher_accept_parent_nokey(private, sk); | 380 | return skcipher_accept_parent_nokey(private, sk); |
diff --git a/crypto/skcipher.c b/crypto/skcipher.c index 11af5fd6a443..0fe2a2923ad0 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c | |||
@@ -598,8 +598,11 @@ static int skcipher_setkey_blkcipher(struct crypto_skcipher *tfm, | |||
598 | err = crypto_blkcipher_setkey(blkcipher, key, keylen); | 598 | err = crypto_blkcipher_setkey(blkcipher, key, keylen); |
599 | crypto_skcipher_set_flags(tfm, crypto_blkcipher_get_flags(blkcipher) & | 599 | crypto_skcipher_set_flags(tfm, crypto_blkcipher_get_flags(blkcipher) & |
600 | CRYPTO_TFM_RES_MASK); | 600 | CRYPTO_TFM_RES_MASK); |
601 | if (err) | ||
602 | return err; | ||
601 | 603 | ||
602 | return err; | 604 | crypto_skcipher_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); |
605 | return 0; | ||
603 | } | 606 | } |
604 | 607 | ||
605 | static int skcipher_crypt_blkcipher(struct skcipher_request *req, | 608 | static int skcipher_crypt_blkcipher(struct skcipher_request *req, |
@@ -674,6 +677,9 @@ static int crypto_init_skcipher_ops_blkcipher(struct crypto_tfm *tfm) | |||
674 | skcipher->ivsize = crypto_blkcipher_ivsize(blkcipher); | 677 | skcipher->ivsize = crypto_blkcipher_ivsize(blkcipher); |
675 | skcipher->keysize = calg->cra_blkcipher.max_keysize; | 678 | skcipher->keysize = calg->cra_blkcipher.max_keysize; |
676 | 679 | ||
680 | if (skcipher->keysize) | ||
681 | crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_NEED_KEY); | ||
682 | |||
677 | return 0; | 683 | return 0; |
678 | } | 684 | } |
679 | 685 | ||
@@ -692,8 +698,11 @@ static int skcipher_setkey_ablkcipher(struct crypto_skcipher *tfm, | |||
692 | crypto_skcipher_set_flags(tfm, | 698 | crypto_skcipher_set_flags(tfm, |
693 | crypto_ablkcipher_get_flags(ablkcipher) & | 699 | crypto_ablkcipher_get_flags(ablkcipher) & |
694 | CRYPTO_TFM_RES_MASK); | 700 | CRYPTO_TFM_RES_MASK); |
701 | if (err) | ||
702 | return err; | ||
695 | 703 | ||
696 | return err; | 704 | crypto_skcipher_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); |
705 | return 0; | ||
697 | } | 706 | } |
698 | 707 | ||
699 | static int skcipher_crypt_ablkcipher(struct skcipher_request *req, | 708 | static int skcipher_crypt_ablkcipher(struct skcipher_request *req, |
@@ -767,6 +776,9 @@ static int crypto_init_skcipher_ops_ablkcipher(struct crypto_tfm *tfm) | |||
767 | sizeof(struct ablkcipher_request); | 776 | sizeof(struct ablkcipher_request); |
768 | skcipher->keysize = calg->cra_ablkcipher.max_keysize; | 777 | skcipher->keysize = calg->cra_ablkcipher.max_keysize; |
769 | 778 | ||
779 | if (skcipher->keysize) | ||
780 | crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_NEED_KEY); | ||
781 | |||
770 | return 0; | 782 | return 0; |
771 | } | 783 | } |
772 | 784 | ||
@@ -796,6 +808,7 @@ static int skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, | |||
796 | { | 808 | { |
797 | struct skcipher_alg *cipher = crypto_skcipher_alg(tfm); | 809 | struct skcipher_alg *cipher = crypto_skcipher_alg(tfm); |
798 | unsigned long alignmask = crypto_skcipher_alignmask(tfm); | 810 | unsigned long alignmask = crypto_skcipher_alignmask(tfm); |
811 | int err; | ||
799 | 812 | ||
800 | if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) { | 813 | if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) { |
801 | crypto_skcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); | 814 | crypto_skcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); |
@@ -803,9 +816,15 @@ static int skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, | |||
803 | } | 816 | } |
804 | 817 | ||
805 | if ((unsigned long)key & alignmask) | 818 | if ((unsigned long)key & alignmask) |
806 | return skcipher_setkey_unaligned(tfm, key, keylen); | 819 | err = skcipher_setkey_unaligned(tfm, key, keylen); |
820 | else | ||
821 | err = cipher->setkey(tfm, key, keylen); | ||
822 | |||
823 | if (err) | ||
824 | return err; | ||
807 | 825 | ||
808 | return cipher->setkey(tfm, key, keylen); | 826 | crypto_skcipher_clear_flags(tfm, CRYPTO_TFM_NEED_KEY); |
827 | return 0; | ||
809 | } | 828 | } |
810 | 829 | ||
811 | static void crypto_skcipher_exit_tfm(struct crypto_tfm *tfm) | 830 | static void crypto_skcipher_exit_tfm(struct crypto_tfm *tfm) |
@@ -834,6 +853,9 @@ static int crypto_skcipher_init_tfm(struct crypto_tfm *tfm) | |||
834 | skcipher->ivsize = alg->ivsize; | 853 | skcipher->ivsize = alg->ivsize; |
835 | skcipher->keysize = alg->max_keysize; | 854 | skcipher->keysize = alg->max_keysize; |
836 | 855 | ||
856 | if (skcipher->keysize) | ||
857 | crypto_skcipher_set_flags(skcipher, CRYPTO_TFM_NEED_KEY); | ||
858 | |||
837 | if (alg->exit) | 859 | if (alg->exit) |
838 | skcipher->base.exit = crypto_skcipher_exit_tfm; | 860 | skcipher->base.exit = crypto_skcipher_exit_tfm; |
839 | 861 | ||