From 871ecc5c5ebfbb9c6e1b17a7ff7a531ed1fab644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Wed, 16 Nov 2016 15:38:39 +0200 Subject: [PATCH 093/104] Fix ablkcipher algorithms usage in v4.8+ kernels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ablkcipher API is not completely removed from kernels <= v4.9. Thus it's still valid to use ablkcipher algorithms. Fix the case when implementers register ablkcipher algorithms and cryptodev casts them to skcipher without checking their type. Note: alg returned by crypto_ablkcipher_alg() is no longer checked to be non-NULL. This is guaranteed by the fact that ablkcipher_tfm (out->async.s) is valid. Fixes: cb186f682679 ("Support skcipher in addition to ablkcipher API") Signed-off-by: Horia Geantă --- cipherapi.h | 4 ---- cryptlib.c | 56 ++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/cipherapi.h b/cipherapi.h index 07d9923..b6ed6c2 100644 --- a/cipherapi.h +++ b/cipherapi.h @@ -6,12 +6,10 @@ #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)) # include -typedef struct ablkcipher_alg cryptodev_blkcipher_alg_t; typedef struct crypto_ablkcipher cryptodev_crypto_blkcipher_t; typedef struct ablkcipher_request cryptodev_blkcipher_request_t; # define cryptodev_crypto_alloc_blkcipher crypto_alloc_ablkcipher -# define cryptodev_crypto_blkcipher_alg crypto_ablkcipher_alg # define cryptodev_crypto_blkcipher_blocksize crypto_ablkcipher_blocksize # define cryptodev_crypto_blkcipher_ivsize crypto_ablkcipher_ivsize # define cryptodev_crypto_blkcipher_alignmask crypto_ablkcipher_alignmask @@ -37,12 +35,10 @@ static inline void cryptodev_blkcipher_request_free(cryptodev_blkcipher_request_ #else #include -typedef struct skcipher_alg cryptodev_blkcipher_alg_t; typedef struct crypto_skcipher cryptodev_crypto_blkcipher_t; typedef struct skcipher_request cryptodev_blkcipher_request_t; # define cryptodev_crypto_alloc_blkcipher crypto_alloc_skcipher -# define cryptodev_crypto_blkcipher_alg crypto_skcipher_alg # define cryptodev_crypto_blkcipher_blocksize crypto_skcipher_blocksize # define cryptodev_crypto_blkcipher_ivsize crypto_skcipher_ivsize # define cryptodev_crypto_blkcipher_alignmask crypto_skcipher_alignmask diff --git a/cryptlib.c b/cryptlib.c index 558d4b8..dcac3ec 100644 --- a/cryptlib.c +++ b/cryptlib.c @@ -39,6 +39,7 @@ #include "cryptodev_int.h" #include "cipherapi.h" +extern const struct crypto_type crypto_givcipher_type; static void cryptodev_complete(struct crypto_async_request *req, int err) { @@ -122,6 +123,19 @@ error: return ret; } +/* Was correct key length supplied? */ +static int check_key_size(size_t keylen, const char *alg_name, + unsigned int min_keysize, unsigned int max_keysize) +{ + if (max_keysize > 0 && unlikely((keylen < min_keysize) || + (keylen > max_keysize))) { + ddebug(1, "Wrong keylen '%zu' for algorithm '%s'. Use %u to %u.", + keylen, alg_name, min_keysize, max_keysize); + return -EINVAL; + } + + return 0; +} int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name, uint8_t *keyp, size_t keylen, int stream, int aead) @@ -129,7 +143,12 @@ int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name, int ret; if (aead == 0) { - cryptodev_blkcipher_alg_t *alg; + unsigned int min_keysize, max_keysize; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) + struct crypto_tfm *tfm; +#else + struct ablkcipher_alg *alg; +#endif out->async.s = cryptodev_crypto_alloc_blkcipher(alg_name, 0, 0); if (unlikely(IS_ERR(out->async.s))) { @@ -137,18 +156,31 @@ int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name, return -EINVAL; } - alg = cryptodev_crypto_blkcipher_alg(out->async.s); - if (alg != NULL) { - /* Was correct key length supplied? */ - if (alg->max_keysize > 0 && - unlikely((keylen < alg->min_keysize) || - (keylen > alg->max_keysize))) { - ddebug(1, "Wrong keylen '%zu' for algorithm '%s'. Use %u to %u.", - keylen, alg_name, alg->min_keysize, alg->max_keysize); - ret = -EINVAL; - goto error; - } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) + tfm = crypto_skcipher_tfm(out->async.s); + if ((tfm->__crt_alg->cra_type == &crypto_ablkcipher_type) || + (tfm->__crt_alg->cra_type == &crypto_givcipher_type)) { + struct ablkcipher_alg *alg; + + alg = &tfm->__crt_alg->cra_ablkcipher; + min_keysize = alg->min_keysize; + max_keysize = alg->max_keysize; + } else { + struct skcipher_alg *alg; + + alg = crypto_skcipher_alg(out->async.s); + min_keysize = alg->min_keysize; + max_keysize = alg->max_keysize; } +#else + alg = crypto_ablkcipher_alg(out->async.s); + min_keysize = alg->min_keysize; + max_keysize = alg->max_keysize; +#endif + ret = check_key_size(keylen, alg_name, min_keysize, + max_keysize); + if (ret) + goto error; out->blocksize = cryptodev_crypto_blkcipher_blocksize(out->async.s); out->ivsize = cryptodev_crypto_blkcipher_ivsize(out->async.s); -- 2.10.2