diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-13 08:50:16 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-13 08:50:16 -0700 |
commit | 39a5101f989e8d2be557136704d53990f9b402c8 (patch) | |
tree | b9c16c6f32508939111fb6d0159d7450713a5f33 /crypto | |
parent | 865c50e1d279671728c2936cb7680eb89355eeea (diff) | |
parent | 3093e7c16e12d729c325adb3c53dde7308cefbd8 (diff) |
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
Pull crypto updates from Herbert Xu:
"API:
- Allow DRBG testing through user-space af_alg
- Add tcrypt speed testing support for keyed hashes
- Add type-safe init/exit hooks for ahash
Algorithms:
- Mark arc4 as obsolete and pending for future removal
- Mark anubis, khazad, sead and tea as obsolete
- Improve boot-time xor benchmark
- Add OSCCA SM2 asymmetric cipher algorithm and use it for integrity
Drivers:
- Fixes and enhancement for XTS in caam
- Add support for XIP8001B hwrng in xiphera-trng
- Add RNG and hash support in sun8i-ce/sun8i-ss
- Allow imx-rngc to be used by kernel entropy pool
- Use crypto engine in omap-sham
- Add support for Ingenic X1830 with ingenic"
* 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (205 commits)
X.509: Fix modular build of public_key_sm2
crypto: xor - Remove unused variable count in do_xor_speed
X.509: fix error return value on the failed path
crypto: bcm - Verify GCM/CCM key length in setkey
crypto: qat - drop input parameter from adf_enable_aer()
crypto: qat - fix function parameters descriptions
crypto: atmel-tdes - use semicolons rather than commas to separate statements
crypto: drivers - use semicolons rather than commas to separate statements
hwrng: mxc-rnga - use semicolons rather than commas to separate statements
hwrng: iproc-rng200 - use semicolons rather than commas to separate statements
hwrng: stm32 - use semicolons rather than commas to separate statements
crypto: xor - use ktime for template benchmarking
crypto: xor - defer load time benchmark to a later time
crypto: hisilicon/zip - fix the uninitalized 'curr_qm_qp_num'
crypto: hisilicon/zip - fix the return value when device is busy
crypto: hisilicon/zip - fix zero length input in GZIP decompress
crypto: hisilicon/zip - fix the uncleared debug registers
lib/mpi: Fix unused variable warnings
crypto: x86/poly1305 - Remove assignments with no effect
hwrng: npcm - modify readl to readb
...
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/Kconfig | 40 | ||||
-rw-r--r-- | crypto/Makefile | 8 | ||||
-rw-r--r-- | crypto/af_alg.c | 14 | ||||
-rw-r--r-- | crypto/ahash.c | 54 | ||||
-rw-r--r-- | crypto/algif_aead.c | 9 | ||||
-rw-r--r-- | crypto/algif_rng.c | 175 | ||||
-rw-r--r-- | crypto/algif_skcipher.c | 2 | ||||
-rw-r--r-- | crypto/arc4.c | 11 | ||||
-rw-r--r-- | crypto/asymmetric_keys/public_key.c | 63 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_cert_parser.c | 27 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 3 | ||||
-rw-r--r-- | crypto/cbc.c | 144 | ||||
-rw-r--r-- | crypto/crc32c_generic.c | 4 | ||||
-rw-r--r-- | crypto/crct10dif_generic.c | 2 | ||||
-rw-r--r-- | crypto/crypto_engine.c | 3 | ||||
-rw-r--r-- | crypto/ecrdsa.c | 1 | ||||
-rw-r--r-- | crypto/internal.h | 16 | ||||
-rw-r--r-- | crypto/jitterentropy-kcapi.c | 2 | ||||
-rw-r--r-- | crypto/proc.c | 4 | ||||
-rw-r--r-- | crypto/rsa-pkcs1pad.c | 1 | ||||
-rw-r--r-- | crypto/sm2.c | 481 | ||||
-rw-r--r-- | crypto/sm2signature.asn1 | 4 | ||||
-rw-r--r-- | crypto/sm3_generic.c | 7 | ||||
-rw-r--r-- | crypto/tcrypt.c | 18 | ||||
-rw-r--r-- | crypto/tcrypt.h | 29 | ||||
-rw-r--r-- | crypto/testmgr.c | 25 | ||||
-rw-r--r-- | crypto/testmgr.h | 59 | ||||
-rw-r--r-- | crypto/xor.c | 69 |
28 files changed, 1122 insertions, 153 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig index 1b57419fa2e7..094ef56ab7b4 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -260,6 +260,23 @@ config CRYPTO_ECRDSA standard algorithms (called GOST algorithms). Only signature verification is implemented. +config CRYPTO_SM2 + tristate "SM2 algorithm" + select CRYPTO_SM3 + select CRYPTO_AKCIPHER + select CRYPTO_MANAGER + select MPILIB + select ASN1 + help + Generic implementation of the SM2 public key algorithm. It was + published by State Encryption Management Bureau, China. + as specified by OSCCA GM/T 0003.1-2012 -- 0003.5-2012. + + References: + https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02 + http://www.oscca.gov.cn/sca/xxgk/2010-12/17/content_1002386.shtml + http://www.gmbz.org.cn/main/bzlb.html + config CRYPTO_CURVE25519 tristate "Curve25519 algorithm" select CRYPTO_KPP @@ -1185,6 +1202,7 @@ config CRYPTO_AES_PPC_SPE config CRYPTO_ANUBIS tristate "Anubis cipher algorithm" + depends on CRYPTO_USER_API_ENABLE_OBSOLETE select CRYPTO_ALGAPI help Anubis cipher algorithm. @@ -1199,6 +1217,7 @@ config CRYPTO_ANUBIS config CRYPTO_ARC4 tristate "ARC4 cipher algorithm" + depends on CRYPTO_USER_API_ENABLE_OBSOLETE select CRYPTO_SKCIPHER select CRYPTO_LIB_ARC4 help @@ -1423,6 +1442,7 @@ config CRYPTO_FCRYPT config CRYPTO_KHAZAD tristate "Khazad cipher algorithm" + depends on CRYPTO_USER_API_ENABLE_OBSOLETE select CRYPTO_ALGAPI help Khazad cipher algorithm. @@ -1486,6 +1506,7 @@ config CRYPTO_CHACHA_MIPS config CRYPTO_SEED tristate "SEED cipher algorithm" + depends on CRYPTO_USER_API_ENABLE_OBSOLETE select CRYPTO_ALGAPI help SEED cipher algorithm (RFC4269). @@ -1612,6 +1633,7 @@ config CRYPTO_SM4 config CRYPTO_TEA tristate "TEA, XTEA and XETA cipher algorithms" + depends on CRYPTO_USER_API_ENABLE_OBSOLETE select CRYPTO_ALGAPI help TEA cipher algorithm. @@ -1870,6 +1892,15 @@ config CRYPTO_USER_API_RNG This option enables the user-spaces interface for random number generator algorithms. +config CRYPTO_USER_API_RNG_CAVP + bool "Enable CAVP testing of DRBG" + depends on CRYPTO_USER_API_RNG && CRYPTO_DRBG + help + This option enables extra API for CAVP testing via the user-space + interface: resetting of DRBG entropy, and providing Additional Data. + This should only be enabled for CAVP testing. You should say + no unless you know what this is. + config CRYPTO_USER_API_AEAD tristate "User-space interface for AEAD cipher algorithms" depends on NET @@ -1881,6 +1912,15 @@ config CRYPTO_USER_API_AEAD This option enables the user-spaces interface for AEAD cipher algorithms. +config CRYPTO_USER_API_ENABLE_OBSOLETE + bool "Enable obsolete cryptographic algorithms for userspace" + depends on CRYPTO_USER_API + default y + help + Allow obsolete cryptographic algorithms to be selected that have + already been phased out from internal use by the kernel, and are + only useful for userspace clients that still rely on them. + config CRYPTO_STATS bool "Crypto usage statistics for User-space" depends on CRYPTO_USER diff --git a/crypto/Makefile b/crypto/Makefile index 4ca12b6044f7..b279483fba50 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -42,6 +42,14 @@ rsa_generic-y += rsa_helper.o rsa_generic-y += rsa-pkcs1pad.o obj-$(CONFIG_CRYPTO_RSA) += rsa_generic.o +$(obj)/sm2signature.asn1.o: $(obj)/sm2signature.asn1.c $(obj)/sm2signature.asn1.h +$(obj)/sm2.o: $(obj)/sm2signature.asn1.h + +sm2_generic-y += sm2signature.asn1.o +sm2_generic-y += sm2.o + +obj-$(CONFIG_CRYPTO_SM2) += sm2_generic.o + crypto_acompress-y := acompress.o crypto_acompress-y += scompress.o obj-$(CONFIG_CRYPTO_ACOMP2) += crypto_acompress.o diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 8be8bec07cdd..d11db80d24cd 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -254,6 +254,14 @@ static int alg_setsockopt(struct socket *sock, int level, int optname, if (!type->setauthsize) goto unlock; err = type->setauthsize(ask->private, optlen); + break; + case ALG_SET_DRBG_ENTROPY: + if (sock->state == SS_CONNECTED) + goto unlock; + if (!type->setentropy) + goto unlock; + + err = type->setentropy(ask->private, optval, optlen); } unlock: @@ -286,6 +294,11 @@ int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern) security_sock_graft(sk2, newsock); security_sk_clone(sk, sk2); + /* + * newsock->ops assigned here to allow type->accept call to override + * them when required. + */ + newsock->ops = type->ops; err = type->accept(ask->private, sk2); nokey = err == -ENOKEY; @@ -304,7 +317,6 @@ int af_alg_accept(struct sock *sk, struct socket *newsock, bool kern) alg_sk(sk2)->parent = sk; alg_sk(sk2)->type = type; - newsock->ops = type->ops; newsock->state = SS_CONNECTED; if (nokey) diff --git a/crypto/ahash.c b/crypto/ahash.c index d9d65d1cc669..c2ca631a111f 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -10,7 +10,6 @@ #include <crypto/internal/hash.h> #include <crypto/scatterwalk.h> -#include <linux/bug.h> #include <linux/err.h> #include <linux/kernel.h> #include <linux/module.h> @@ -46,10 +45,7 @@ static int hash_walk_next(struct crypto_hash_walk *walk) unsigned int nbytes = min(walk->entrylen, ((unsigned int)(PAGE_SIZE)) - offset); - if (walk->flags & CRYPTO_ALG_ASYNC) - walk->data = kmap(walk->pg); - else - walk->data = kmap_atomic(walk->pg); + walk->data = kmap_atomic(walk->pg); walk->data += offset; if (offset & alignmask) { @@ -99,16 +95,8 @@ int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) } } - if (walk->flags & CRYPTO_ALG_ASYNC) - kunmap(walk->pg); - else { - kunmap_atomic(walk->data); - /* - * The may sleep test only makes sense for sync users. - * Async users don't need to sleep here anyway. - */ - crypto_yield(walk->flags); - } + kunmap_atomic(walk->data); + crypto_yield(walk->flags); if (err) return err; @@ -140,33 +128,12 @@ int crypto_hash_walk_first(struct ahash_request *req, walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req)); walk->sg = req->src; - walk->flags = req->base.flags & CRYPTO_TFM_REQ_MASK; + walk->flags = req->base.flags; return hash_walk_new_entry(walk); } EXPORT_SYMBOL_GPL(crypto_hash_walk_first); -int crypto_ahash_walk_first(struct ahash_request *req, - struct crypto_hash_walk *walk) -{ - walk->total = req->nbytes; - - if (!walk->total) { - walk->entrylen = 0; - return 0; - } - - walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req)); - walk->sg = req->src; - walk->flags = req->base.flags & CRYPTO_TFM_REQ_MASK; - walk->flags |= CRYPTO_ALG_ASYNC; - - BUILD_BUG_ON(CRYPTO_TFM_REQ_MASK & CRYPTO_ALG_ASYNC); - - return hash_walk_new_entry(walk); -} -EXPORT_SYMBOL_GPL(crypto_ahash_walk_first); - static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen) { @@ -477,6 +444,14 @@ static int ahash_def_finup(struct ahash_request *req) return ahash_def_finup_finish1(req, err); } +static void crypto_ahash_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_ahash *hash = __crypto_ahash_cast(tfm); + struct ahash_alg *alg = crypto_ahash_alg(hash); + + alg->exit_tfm(hash); +} + static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) { struct crypto_ahash *hash = __crypto_ahash_cast(tfm); @@ -500,7 +475,10 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) ahash_set_needkey(hash); } - return 0; + if (alg->exit_tfm) + tfm->exit = crypto_ahash_exit_tfm; + + return alg->init_tfm ? alg->init_tfm(hash) : 0; } static unsigned int crypto_ahash_extsize(struct crypto_alg *alg) diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index 21efa786f09c..42493b4d8ce4 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -78,7 +78,7 @@ static int crypto_aead_copy_sgl(struct crypto_sync_skcipher *null_tfm, SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm); skcipher_request_set_sync_tfm(skreq, null_tfm); - skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_BACKLOG, + skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); skcipher_request_set_crypt(skreq, src, dst, len, NULL); @@ -120,7 +120,7 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, /* * Make sure sufficient data is present -- note, the same check is - * is also present in sendmsg/sendpage. The checks in sendpage/sendmsg + * also present in sendmsg/sendpage. The checks in sendpage/sendmsg * shall provide an information to the data sender that something is * wrong, but they are irrelevant to maintain the kernel integrity. * We need this check here too in case user space decides to not honor @@ -291,19 +291,20 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, areq->outlen = outlen; aead_request_set_callback(&areq->cra_u.aead_req, - CRYPTO_TFM_REQ_MAY_BACKLOG, + CRYPTO_TFM_REQ_MAY_SLEEP, af_alg_async_cb, areq); err = ctx->enc ? crypto_aead_encrypt(&areq->cra_u.aead_req) : crypto_aead_decrypt(&areq->cra_u.aead_req); /* AIO operation in progress */ - if (err == -EINPROGRESS || err == -EBUSY) + if (err == -EINPROGRESS) return -EIOCBQUEUED; sock_put(sk); } else { /* Synchronous operation */ aead_request_set_callback(&areq->cra_u.aead_req, + CRYPTO_TFM_REQ_MAY_SLEEP | CRYPTO_TFM_REQ_MAY_BACKLOG, crypto_req_done, &ctx->wait); err = crypto_wait_req(ctx->enc ? diff --git a/crypto/algif_rng.c b/crypto/algif_rng.c index 6300e0566dc5..407408c43730 100644 --- a/crypto/algif_rng.c +++ b/crypto/algif_rng.c @@ -38,6 +38,7 @@ * DAMAGE. */ +#include <linux/capability.h> #include <linux/module.h> #include <crypto/rng.h> #include <linux/random.h> @@ -53,15 +54,26 @@ struct rng_ctx { #define MAXSIZE 128 unsigned int len; struct crypto_rng *drng; + u8 *addtl; + size_t addtl_len; }; -static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, - int flags) +struct rng_parent_ctx { + struct crypto_rng *drng; + u8 *entropy; +}; + +static void rng_reset_addtl(struct rng_ctx *ctx) { - struct sock *sk = sock->sk; - struct alg_sock *ask = alg_sk(sk); - struct rng_ctx *ctx = ask->private; - int err; + kfree_sensitive(ctx->addtl); + ctx->addtl = NULL; + ctx->addtl_len = 0; +} + +static int _rng_recvmsg(struct crypto_rng *drng, struct msghdr *msg, size_t len, + u8 *addtl, size_t addtl_len) +{ + int err = 0; int genlen = 0; u8 result[MAXSIZE]; @@ -82,7 +94,7 @@ static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, * seeding as they automatically seed. The X9.31 DRNG will return * an error if it was not seeded properly. */ - genlen = crypto_rng_get_bytes(ctx->drng, result, len); + genlen = crypto_rng_generate(drng, addtl, addtl_len, result, len); if (genlen < 0) return genlen; @@ -92,6 +104,63 @@ static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, return err ? err : len; } +static int rng_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, + int flags) +{ + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); + struct rng_ctx *ctx = ask->private; + + return _rng_recvmsg(ctx->drng, msg, len, NULL, 0); +} + +static int rng_test_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, + int flags) +{ + struct sock *sk = sock->sk; + struct alg_sock *ask = alg_sk(sk); + struct rng_ctx *ctx = ask->private; + int ret; + + lock_sock(sock->sk); + ret = _rng_recvmsg(ctx->drng, msg, len, ctx->addtl, ctx->addtl_len); + rng_reset_addtl(ctx); + release_sock(sock->sk); + + return ret; +} + +static int rng_test_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) +{ + int err; + struct alg_sock *ask = alg_sk(sock->sk); + struct rng_ctx *ctx = ask->private; + + lock_sock(sock->sk); + if (len > MAXSIZE) { + err = -EMSGSIZE; + goto unlock; + } + + rng_reset_addtl(ctx); + ctx->addtl = kmalloc(len, GFP_KERNEL); + if (!ctx->addtl) { + err = -ENOMEM; + goto unlock; + } + + err = memcpy_from_msg(ctx->addtl, msg, len); + if (err) { + rng_reset_addtl(ctx); + goto unlock; + } + ctx->addtl_len = len; + +unlock: + release_sock(sock->sk); + return err ? err : len; +} + static struct proto_ops algif_rng_ops = { .family = PF_ALG, @@ -111,14 +180,53 @@ static struct proto_ops algif_rng_ops = { .recvmsg = rng_recvmsg, }; +static struct proto_ops __maybe_unused algif_rng_test_ops = { + .family = PF_ALG, + + .connect = sock_no_connect, + .socketpair = sock_no_socketpair, + .getname = sock_no_getname, + .ioctl = sock_no_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .mmap = sock_no_mmap, + .bind = sock_no_bind, + .accept = sock_no_accept, + .sendpage = sock_no_sendpage, + + .release = af_alg_release, + .recvmsg = rng_test_recvmsg, + .sendmsg = rng_test_sendmsg, +}; + static void *rng_bind(const char *name, u32 type, u32 mask) { - return crypto_alloc_rng(name, type, mask); + struct rng_parent_ctx *pctx; + struct crypto_rng *rng; + + pctx = kzalloc(sizeof(*pctx), GFP_KERNEL); + if (!pctx) + return ERR_PTR(-ENOMEM); + + rng = crypto_alloc_rng(name, type, mask); + if (IS_ERR(rng)) { + kfree(pctx); + return ERR_CAST(rng); + } + + pctx->drng = rng; + return pctx; } static void rng_release(void *private) { - crypto_free_rng(private); + struct rng_parent_ctx *pctx = private; + + if (unlikely(!pctx)) + return; + crypto_free_rng(pctx->drng); + kfree_sensitive(pctx->entropy); + kfree_sensitive(pctx); } static void rng_sock_destruct(struct sock *sk) @@ -126,6 +234,7 @@ static void rng_sock_destruct(struct sock *sk) struct alg_sock *ask = alg_sk(sk); struct rng_ctx *ctx = ask->private; + rng_reset_addtl(ctx); sock_kfree_s(sk, ctx, ctx->len); af_alg_release_parent(sk); } @@ -133,6 +242,7 @@ static void rng_sock_destruct(struct sock *sk) static int rng_accept_parent(void *private, struct sock *sk) { struct rng_ctx *ctx; + struct rng_parent_ctx *pctx = private; struct alg_sock *ask = alg_sk(sk); unsigned int len = sizeof(*ctx); @@ -141,6 +251,8 @@ static int rng_accept_parent(void *private, struct sock *sk) return -ENOMEM; ctx->len = len; + ctx->addtl = NULL; + ctx->addtl_len = 0; /* * No seeding done at that point -- if multiple accepts are @@ -148,20 +260,58 @@ static int rng_accept_parent(void *private, struct sock *sk) * state of the RNG. */ - ctx->drng = private; + ctx->drng = pctx->drng; ask->private = ctx; sk->sk_destruct = rng_sock_destruct; + /* + * Non NULL pctx->entropy means that CAVP test has been initiated on + * this socket, replace proto_ops algif_rng_ops with algif_rng_test_ops. + */ + if (IS_ENABLED(CONFIG_CRYPTO_USER_API_RNG_CAVP) && pctx->entropy) + sk->sk_socket->ops = &algif_rng_test_ops; + return 0; } static int rng_setkey(void *private, const u8 *seed, unsigned int seedlen) { + struct rng_parent_ctx *pctx = private; /* * Check whether seedlen is of sufficient size is done in RNG * implementations. */ - return crypto_rng_reset(private, seed, seedlen); + return crypto_rng_reset(pctx->drng, seed, seedlen); +} + +static int __maybe_unused rng_setentropy(void *private, sockptr_t entropy, + unsigned int len) +{ + struct rng_parent_ctx *pctx = private; + u8 *kentropy = NULL; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (pctx->entropy) + return -EINVAL; + + if (len > MAXSIZE) + return -EMSGSIZE; + + if (len) { + kentropy = memdup_sockptr(entropy, len); + if (IS_ERR(kentropy)) + return PTR_ERR(kentropy); + } + + crypto_rng_alg(pctx->drng)->set_ent(pctx->drng, kentropy, len); + /* + * Since rng doesn't perform any memory management for the entropy + * buffer, save kentropy pointer to pctx now to free it after use. + */ + pctx->entropy = kentropy; + return 0; } static const struct af_alg_type algif_type_rng = { @@ -169,6 +319,9 @@ static const struct af_alg_type algif_type_rng = { .release = rng_release, .accept = rng_accept_parent, .setkey = rng_setkey, +#ifdef CONFIG_CRYPTO_USER_API_RNG_CAVP + .setentropy = rng_setentropy, +#endif .ops = &algif_rng_ops, .name = "rng", .owner = THIS_MODULE diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 478f3b8f5bd5..ee8890ee8f33 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -123,7 +123,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, crypto_skcipher_decrypt(&areq->cra_u.skcipher_req); /* AIO operation in progress */ - if (err == -EINPROGRESS || err == -EBUSY) + if (err == -EINPROGRESS) return -EIOCBQUEUED; sock_put(sk); diff --git a/crypto/arc4.c b/crypto/arc4.c index aa79571dbd49..3254dcc34368 100644 --- a/crypto/arc4.c +++ b/crypto/arc4.c @@ -11,7 +11,9 @@ #include <crypto/arc4.h> #include <crypto/internal/skcipher.h> #include <linux/init.h> +#include <linux/kernel.h> #include <linux/module.h> +#include <linux/sched.h> static int crypto_arc4_setkey(struct crypto_skcipher *tfm, const u8 *in_key, unsigned int key_len) @@ -39,6 +41,14 @@ static int crypto_arc4_crypt(struct skcipher_request *req) return err; } +static int crypto_arc4_init(struct crypto_skcipher *tfm) +{ + pr_warn_ratelimited("\"%s\" (%ld) uses obsolete ecb(arc4) skcipher\n", + current->comm, (unsigned long)current->pid); + + return 0; +} + static struct skcipher_alg arc4_alg = { /* * For legacy reasons, this is named "ecb(arc4)", not "arc4". @@ -55,6 +65,7 @@ static struct skcipher_alg arc4_alg = { .setkey = crypto_arc4_setkey, .encrypt = crypto_arc4_crypt, .decrypt = crypto_arc4_crypt, + .init = crypto_arc4_init, }; static int __init arc4_init(void) diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index d8410ffd7f12..8892908ad58c 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -17,6 +17,8 @@ #include <keys/asymmetric-subtype.h> #include <crypto/public_key.h> #include <crypto/akcipher.h> +#include <crypto/sm2.h> +#include <crypto/sm3_base.h> MODULE_DESCRIPTION("In-software asymmetric public-key subtype"); MODULE_AUTHOR("Red Hat, Inc."); @@ -246,6 +248,61 @@ error_free_tfm: return ret; } +#if IS_REACHABLE(CONFIG_CRYPTO_SM2) +static int cert_sig_digest_update(const struct public_key_signature *sig, + struct crypto_akcipher *tfm_pkey) +{ + struct crypto_shash *tfm; + struct shash_desc *desc; + size_t desc_size; + unsigned char dgst[SM3_DIGEST_SIZE]; + int ret; + + BUG_ON(!sig->data); + + ret = sm2_compute_z_digest(tfm_pkey, SM2_DEFAULT_USERID, + SM2_DEFAULT_USERID_LEN, dgst); + if (ret) + return ret; + + tfm = crypto_alloc_shash(sig->hash_algo, 0, 0); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); + + desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); + desc = kzalloc(desc_size, GFP_KERNEL); + if (!desc) { + ret = -ENOMEM; + goto error_free_tfm; + } + + desc->tfm = tfm; + + ret = crypto_shash_init(desc); + if (ret < 0) + goto error_free_desc; + + ret = crypto_shash_update(desc, dgst, SM3_DIGEST_SIZE); + if (ret < 0) + goto error_free_desc; + + ret = crypto_shash_finup(desc, sig->data, sig->data_size, sig->digest); + +error_free_desc: + kfree(desc); +error_free_tfm: + crypto_free_shash(tfm); + return ret; +} +#else +static inline int cert_sig_digest_update( + const struct public_key_signature *sig, + struct crypto_akcipher *tfm_pkey) +{ + return -ENOTSUPP; +} +#endif /* ! IS_REACHABLE(CONFIG_CRYPTO_SM2) */ + /* * Verify a signature using a public key. */ @@ -299,6 +356,12 @@ int public_key_verify_signature(const struct public_key *pkey, if (ret) goto error_free_key; + if (strcmp(sig->pkey_algo, "sm2") == 0 && sig->data_size) { + ret = cert_sig_digest_update(sig, tfm); + if (ret) + goto error_free_key; + } + sg_init_table(src_sg, 2); sg_set_buf(&src_sg[0], sig->s, sig->s_size); sg_set_buf(&src_sg[1], sig->digest, sig->digest_size); diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 26ec20ef4899..52c9b455fc7d 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -234,6 +234,10 @@ int x509_note_pkey_algo(void *context, size_t hdrlen, case OID_gost2012Signature512: ctx->cert->sig->hash_algo = "streebog512"; goto ecrdsa; + + case OID_SM2_with_SM3: + ctx->cert->sig->hash_algo = "sm3"; + goto sm2; } rsa_pkcs1: @@ -246,6 +250,11 @@ ecrdsa: ctx->cert->sig->encoding = "raw"; ctx->algo_oid = ctx->last_oid; return 0; +sm2: + ctx->cert->sig->pkey_algo = "sm2"; + ctx->cert->sig->encoding = "raw"; + ctx->algo_oid = ctx->last_oid; + return 0; } /* @@ -266,7 +275,8 @@ int x509_note_signature(void *context, size_t hdrlen, } if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 || - strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0) { + strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0 || + strcmp(ctx->cert->sig->pkey_algo, "sm2") == 0) { /* Discard the BIT STRING metadata */ if (vlen < 1 || *(const u8 *)value != 0) return -EBADMSG; @@ -451,13 +461,20 @@ int x509_extract_key_data(void *context, size_t hdrlen, struct x509_parse_context *ctx = context; ctx->key_algo = ctx->last_oid; - if (ctx->last_oid == OID_rsaEncryption) + switch (ctx->last_oid) { + case OID_rsaEncryption: ctx->cert->pub->pkey_algo = "rsa"; - else if (ctx->last_oid == OID_gost2012PKey256 || - ctx->last_oid == OID_gost2012PKey512) + break; + case OID_gost2012PKey256: + case OID_gost2012PKey512: ctx->cert->pub->pkey_algo = "ecrdsa"; - else + break; + case OID_id_ecPublicKey: + ctx->cert->pub->pkey_algo = "sm2"; + break; + default: return -ENOPKG; + } /* Discard the BIT STRING metadata */ if (vlen < 1 || *(const u8 *)value != 0) diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index d964cc82b69c..ae450eb8be14 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -30,6 +30,9 @@ int x509_get_sig_params(struct x509_certificate *cert) pr_devel("==>%s()\n", __func__); + sig->data = cert->tbs; + sig->data_size = cert->tbs_size; + if (!cert->pub->pkey_algo) cert->unsupported_key = true; diff --git a/crypto/cbc.c b/crypto/cbc.c index e6f6273a7d39..0d9509dff891 100644 --- a/crypto/cbc.c +++ b/crypto/cbc.c @@ -6,7 +6,6 @@ */ #include <crypto/algapi.h> -#include <crypto/cbc.h> #include <crypto/internal/skcipher.h> #include <linux/err.h> #include <linux/init.h> @@ -14,34 +13,157 @@ #include <linux/log2.h> #include <linux/module.h> -static inline void crypto_cbc_encrypt_one(struct crypto_skcipher *tfm, - const u8 *src, u8 *dst) +static int crypto_cbc_encrypt_segment(struct skcipher_walk *walk, + struct crypto_skcipher *skcipher) { - crypto_cipher_encrypt_one(skcipher_cipher_simple(tfm), dst, src); + unsigned int bsize = crypto_skcipher_blocksize(skcipher); + void (*fn)(struct crypto_tfm *, u8 *, const u8 *); + unsigned int nbytes = walk->nbytes; + u8 *src = walk->src.virt.addr; + u8 *dst = walk->dst.virt.addr; + struct crypto_cipher *cipher; + struct crypto_tfm *tfm; + u8 *iv = walk->iv; + + cipher = skcipher_cipher_simple(skcipher); + tfm = crypto_cipher_tfm(cipher); + fn = crypto_cipher_alg(cipher)->cia_encrypt; + + do { + crypto_xor(iv, src, bsize); + fn(tfm, dst, iv); + memcpy(iv, dst, bsize); + + src += bsize; + dst += bsize; + } while ((nbytes -= bsize) >= bsize); + + return nbytes; +} + +static int crypto_cbc_encrypt_inplace(struct skcipher_walk *walk, + struct crypto_skcipher *skcipher) +{ + unsigned int bsize = crypto_skcipher_blocksize(skcipher); + void (*fn)(struct crypto_tfm *, u8 *, const u8 *); + unsigned int nbytes = walk->nbytes; + u8 *src = walk->src.virt.addr; + struct crypto_cipher *cipher; + struct crypto_tfm *tfm; + u8 *iv = walk->iv; + + cipher = skcipher_cipher_simple(skcipher); + tfm = crypto_cipher_tfm(cipher); + fn = crypto_cipher_alg(cipher)->cia_encrypt; + + do { + crypto_xor(src, iv, bsize); + fn(tfm, src, src); + iv = src; + + src += bsize; + } while ((nbytes -= bsize) >= bsize); + + memcpy(walk->iv, iv, bsize); + + return nbytes; } static int crypto_cbc_encrypt(struct skcipher_request *req) { - return crypto_cbc_encrypt_walk(req, crypto_cbc_encrypt_one); + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct skcipher_walk walk; |