diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-04 09:11:12 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-04 09:11:12 -0800 |
commit | ccc9d4a6d640cbde05d519edeb727881646cf71b (patch) | |
tree | 736c90b100703501d5e3fa3eccc57a48f70bef14 /crypto | |
parent | 66ef3493d4bb387f5a83915e33dc893102fd1b43 (diff) | |
parent | 271817a3e92c0455bda5856d87eca244ad67d3a2 (diff) |
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
Pull crypto update from Herbert Xu:
"API:
- Add support for cipher output IVs in testmgr
- Add missing crypto_ahash_blocksize helper
- Mark authenc and des ciphers as not allowed under FIPS.
Algorithms:
- Add CRC support to 842 compression
- Add keywrap algorithm
- A number of changes to the akcipher interface:
+ Separate functions for setting public/private keys.
+ Use SG lists.
Drivers:
- Add Intel SHA Extension optimised SHA1 and SHA256
- Use dma_map_sg instead of custom functions in crypto drivers
- Add support for STM32 RNG
- Add support for ST RNG
- Add Device Tree support to exynos RNG driver
- Add support for mxs-dcp crypto device on MX6SL
- Add xts(aes) support to caam
- Add ctr(aes) and xts(aes) support to qat
- A large set of fixes from Russell King for the marvell/cesa driver"
* 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (115 commits)
crypto: asymmetric_keys - Fix unaligned access in x509_get_sig_params()
crypto: akcipher - Don't #include crypto/public_key.h as the contents aren't used
hwrng: exynos - Add Device Tree support
hwrng: exynos - Fix missing configuration after suspend to RAM
hwrng: exynos - Add timeout for waiting on init done
dt-bindings: rng: Describe Exynos4 PRNG bindings
crypto: marvell/cesa - use __le32 for hardware descriptors
crypto: marvell/cesa - fix missing cpu_to_le32() in mv_cesa_dma_add_op()
crypto: marvell/cesa - use memcpy_fromio()/memcpy_toio()
crypto: marvell/cesa - use gfp_t for gfp flags
crypto: marvell/cesa - use dma_addr_t for cur_dma
crypto: marvell/cesa - use readl_relaxed()/writel_relaxed()
crypto: caam - fix indentation of close braces
crypto: caam - only export the state we really need to export
crypto: caam - fix non-block aligned hash calculation
crypto: caam - avoid needlessly saving and restoring caam_hash_ctx
crypto: caam - print errno code when hash registration fails
crypto: marvell/cesa - fix memory leak
crypto: marvell/cesa - fix first-fragment handling in mv_cesa_ahash_dma_last_req()
crypto: marvell/cesa - rearrange handling for sw padded hashes
...
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/Kconfig | 17 | ||||
-rw-r--r-- | crypto/Makefile | 10 | ||||
-rw-r--r-- | crypto/akcipher.c | 1 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_verify.c | 5 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_cert_parser.c | 6 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 5 | ||||
-rw-r--r-- | crypto/jitterentropy-kcapi.c | 4 | ||||
-rw-r--r-- | crypto/keywrap.c | 419 | ||||
-rw-r--r-- | crypto/rsa.c | 83 | ||||
-rw-r--r-- | crypto/rsa_helper.c | 42 | ||||
-rw-r--r-- | crypto/rsakey.asn1 | 5 | ||||
-rw-r--r-- | crypto/rsaprivkey.asn1 | 11 | ||||
-rw-r--r-- | crypto/rsapubkey.asn1 | 4 | ||||
-rw-r--r-- | crypto/skcipher.c | 4 | ||||
-rw-r--r-- | crypto/tcrypt.c | 17 | ||||
-rw-r--r-- | crypto/testmgr.c | 83 | ||||
-rw-r--r-- | crypto/testmgr.h | 77 |
17 files changed, 677 insertions, 116 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig index 48ee3e175dac..7240821137fd 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -348,6 +348,13 @@ config CRYPTO_XTS key size 256, 384 or 512 bits. This implementation currently can't handle a sectorsize which is not a multiple of 16 bytes. +config CRYPTO_KEYWRAP + tristate "Key wrapping support" + select CRYPTO_BLKCIPHER + help + Support for key wrapping (NIST SP800-38F / RFC3394) without + padding. + comment "Hash modes" config CRYPTO_CMAC @@ -597,17 +604,18 @@ config CRYPTO_SHA1 SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). config CRYPTO_SHA1_SSSE3 - tristate "SHA1 digest algorithm (SSSE3/AVX/AVX2)" + tristate "SHA1 digest algorithm (SSSE3/AVX/AVX2/SHA-NI)" depends on X86 && 64BIT select CRYPTO_SHA1 select CRYPTO_HASH help SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented using Supplemental SSE3 (SSSE3) instructions or Advanced Vector - Extensions (AVX/AVX2), when available. + Extensions (AVX/AVX2) or SHA-NI(SHA Extensions New Instructions), + when available. config CRYPTO_SHA256_SSSE3 - tristate "SHA256 digest algorithm (SSSE3/AVX/AVX2)" + tristate "SHA256 digest algorithm (SSSE3/AVX/AVX2/SHA-NI)" depends on X86 && 64BIT select CRYPTO_SHA256 select CRYPTO_HASH @@ -615,7 +623,8 @@ config CRYPTO_SHA256_SSSE3 SHA-256 secure hash standard (DFIPS 180-2) implemented using Supplemental SSE3 (SSSE3) instructions, or Advanced Vector Extensions version 1 (AVX1), or Advanced Vector Extensions - version 2 (AVX2) instructions, when available. + version 2 (AVX2) instructions, or SHA-NI (SHA Extensions New + Instructions) when available. config CRYPTO_SHA512_SSSE3 tristate "SHA512 digest algorithm (SSSE3/AVX/AVX2)" diff --git a/crypto/Makefile b/crypto/Makefile index e2c59819b236..f7aba923458d 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -31,10 +31,13 @@ obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o obj-$(CONFIG_CRYPTO_PCOMP2) += pcompress.o obj-$(CONFIG_CRYPTO_AKCIPHER2) += akcipher.o -$(obj)/rsakey-asn1.o: $(obj)/rsakey-asn1.c $(obj)/rsakey-asn1.h -clean-files += rsakey-asn1.c rsakey-asn1.h +$(obj)/rsapubkey-asn1.o: $(obj)/rsapubkey-asn1.c $(obj)/rsapubkey-asn1.h +$(obj)/rsaprivkey-asn1.o: $(obj)/rsaprivkey-asn1.c $(obj)/rsaprivkey-asn1.h +clean-files += rsapubkey-asn1.c rsapubkey-asn1.h +clean-files += rsaprivkey-asn1.c rsaprivkey-asn1.h -rsa_generic-y := rsakey-asn1.o +rsa_generic-y := rsapubkey-asn1.o +rsa_generic-y += rsaprivkey-asn1.o rsa_generic-y += rsa.o rsa_generic-y += rsa_helper.o obj-$(CONFIG_CRYPTO_RSA) += rsa_generic.o @@ -67,6 +70,7 @@ obj-$(CONFIG_CRYPTO_CTS) += cts.o obj-$(CONFIG_CRYPTO_LRW) += lrw.o obj-$(CONFIG_CRYPTO_XTS) += xts.o obj-$(CONFIG_CRYPTO_CTR) += ctr.o +obj-$(CONFIG_CRYPTO_KEYWRAP) += keywrap.o obj-$(CONFIG_CRYPTO_GCM) += gcm.o obj-$(CONFIG_CRYPTO_CCM) += ccm.o obj-$(CONFIG_CRYPTO_CHACHA20POLY1305) += chacha20poly1305.o diff --git a/crypto/akcipher.c b/crypto/akcipher.c index 528ae6aa9bff..120ec042ec9e 100644 --- a/crypto/akcipher.c +++ b/crypto/akcipher.c @@ -21,7 +21,6 @@ #include <linux/cryptouser.h> #include <net/netlink.h> #include <crypto/akcipher.h> -#include <crypto/public_key.h> #include "internal.h" #ifdef CONFIG_NET diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index d20c0b4b880e..325575caf6b4 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c @@ -49,11 +49,12 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, sinfo->sig.digest_size = digest_size = crypto_shash_digestsize(tfm); ret = -ENOMEM; - digest = kzalloc(digest_size + desc_size, GFP_KERNEL); + digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size, + GFP_KERNEL); if (!digest) goto error_no_desc; - desc = digest + digest_size; + desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc)); desc->tfm = tfm; desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index af71878dc15b..3000ea3b6687 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -546,9 +546,9 @@ int x509_decode_time(time64_t *_t, size_t hdrlen, if (year < 1970 || mon < 1 || mon > 12 || day < 1 || day > mon_len || - hour < 0 || hour > 23 || - min < 0 || min > 59 || - sec < 0 || sec > 59) + hour > 23 || + min > 59 || + sec > 59) goto invalid_time; *_t = mktime64(year, mon, day, hour, min, sec); diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 197096632412..68c3c40501ab 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -194,14 +194,15 @@ int x509_get_sig_params(struct x509_certificate *cert) * digest storage space. */ ret = -ENOMEM; - digest = kzalloc(digest_size + desc_size, GFP_KERNEL); + digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size, + GFP_KERNEL); if (!digest) goto error; cert->sig.digest = digest; cert->sig.digest_size = digest_size; - desc = digest + digest_size; + desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc)); desc->tfm = tfm; desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; diff --git a/crypto/jitterentropy-kcapi.c b/crypto/jitterentropy-kcapi.c index ceea83d13168..597cedd3531c 100644 --- a/crypto/jitterentropy-kcapi.c +++ b/crypto/jitterentropy-kcapi.c @@ -98,10 +98,6 @@ void jent_get_nstime(__u64 *out) * If random_get_entropy does not return a value (which is possible on, * for example, MIPS), invoke __getnstimeofday * hoping that there are timers we can work with. - * - * The list of available timers can be obtained from - * /sys/devices/system/clocksource/clocksource0/available_clocksource - * and are registered with clocksource_register() */ if ((0 == tmp) && (0 == __getnstimeofday(&ts))) { diff --git a/crypto/keywrap.c b/crypto/keywrap.c new file mode 100644 index 000000000000..b1d106ce55f3 --- /dev/null +++ b/crypto/keywrap.c @@ -0,0 +1,419 @@ +/* + * Key Wrapping: RFC3394 / NIST SP800-38F + * + * Copyright (C) 2015, Stephan Mueller <smueller@chronox.de> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU General Public License, in which case the provisions of the GPL2 + * are required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +/* + * Note for using key wrapping: + * + * * The result of the encryption operation is the ciphertext starting + * with the 2nd semiblock. The first semiblock is provided as the IV. + * The IV used to start the encryption operation is the default IV. + * + * * The input for the decryption is the first semiblock handed in as an + * IV. The ciphertext is the data starting with the 2nd semiblock. The + * return code of the decryption operation will be EBADMSG in case an + * integrity error occurs. + * + * To obtain the full result of an encryption as expected by SP800-38F, the + * caller must allocate a buffer of plaintext + 8 bytes: + * + * unsigned int datalen = ptlen + crypto_skcipher_ivsize(tfm); + * u8 data[datalen]; + * u8 *iv = data; + * u8 *pt = data + crypto_skcipher_ivsize(tfm); + * <ensure that pt contains the plaintext of size ptlen> + * sg_init_one(&sg, ptdata, ptlen); + * skcipher_request_set_crypt(req, &sg, &sg, ptlen, iv); + * + * ==> After encryption, data now contains full KW result as per SP800-38F. + * + * In case of decryption, ciphertext now already has the expected length + * and must be segmented appropriately: + * + * unsigned int datalen = CTLEN; + * u8 data[datalen]; + * <ensure that data contains full ciphertext> + * u8 *iv = data; + * u8 *ct = data + crypto_skcipher_ivsize(tfm); + * unsigned int ctlen = datalen - crypto_skcipher_ivsize(tfm); + * sg_init_one(&sg, ctdata, ctlen); + * skcipher_request_set_crypt(req, &sg, &sg, ptlen, iv); + * + * ==> After decryption (which hopefully does not return EBADMSG), the ct + * pointer now points to the plaintext of size ctlen. + * + * Note 2: KWP is not implemented as this would defy in-place operation. + * If somebody wants to wrap non-aligned data, he should simply pad + * the input with zeros to fill it up to the 8 byte boundary. + */ + +#include <linux/module.h> +#include <linux/crypto.h> +#include <linux/scatterlist.h> +#include <crypto/scatterwalk.h> +#include <crypto/internal/skcipher.h> + +struct crypto_kw_ctx { + struct crypto_cipher *child; +}; + +struct crypto_kw_block { +#define SEMIBSIZE 8 + u8 A[SEMIBSIZE]; + u8 R[SEMIBSIZE]; +}; + +/* convert 64 bit integer into its string representation */ +static inline void crypto_kw_cpu_to_be64(u64 val, u8 *buf) +{ + __be64 *a = (__be64 *)buf; + + *a = cpu_to_be64(val); +} + +/* + * Fast forward the SGL to the "end" length minus SEMIBSIZE. + * The start in the SGL defined by the fast-forward is returned with + * the walk variable + */ +static void crypto_kw_scatterlist_ff(struct scatter_walk *walk, + struct scatterlist *sg, + unsigned int end) +{ + unsigned int skip = 0; + + /* The caller should only operate on full SEMIBLOCKs. */ + BUG_ON(end < SEMIBSIZE); + + skip = end - SEMIBSIZE; + while (sg) { + if (sg->length > skip) { + scatterwalk_start(walk, sg); + scatterwalk_advance(walk, skip); + break; + } else + skip -= sg->length; + + sg = sg_next(sg); + } +} + +static int crypto_kw_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct crypto_blkcipher *tfm = desc->tfm; + struct crypto_kw_ctx *ctx = crypto_blkcipher_ctx(tfm); + struct crypto_cipher *child = ctx->child; + + unsigned long alignmask = max_t(unsigned long, SEMIBSIZE, + crypto_cipher_alignmask(child)); + unsigned int i; + + u8 blockbuf[sizeof(struct crypto_kw_block) + alignmask]; + struct crypto_kw_block *block = (struct crypto_kw_block *) + PTR_ALIGN(blockbuf + 0, alignmask + 1); + + u64 t = 6 * ((nbytes) >> 3); + struct scatterlist *lsrc, *ldst; + int ret = 0; + + /* + * Require at least 2 semiblocks (note, the 3rd semiblock that is + * required by SP800-38F is the IV. + */ + if (nbytes < (2 * SEMIBSIZE) || nbytes % SEMIBSIZE) + return -EINVAL; + + /* Place the IV into block A */ + memcpy(block->A, desc->info, SEMIBSIZE); + + /* + * src scatterlist is read-only. dst scatterlist is r/w. During the + * first loop, lsrc points to src and ldst to dst. For any + * subsequent round, the code operates on dst only. + */ + lsrc = src; + ldst = dst; + + for (i = 0; i < 6; i++) { + u8 tbe_buffer[SEMIBSIZE + alignmask]; + /* alignment for the crypto_xor and the _to_be64 operation */ + u8 *tbe = PTR_ALIGN(tbe_buffer + 0, alignmask + 1); + unsigned int tmp_nbytes = nbytes; + struct scatter_walk src_walk, dst_walk; + + while (tmp_nbytes) { + /* move pointer by tmp_nbytes in the SGL */ + crypto_kw_scatterlist_ff(&src_walk, lsrc, tmp_nbytes); + /* get the source block */ + scatterwalk_copychunks(block->R, &src_walk, SEMIBSIZE, + false); + + /* perform KW operation: get counter as byte string */ + crypto_kw_cpu_to_be64(t, tbe); + /* perform KW operation: modify IV with counter */ + crypto_xor(block->A, tbe, SEMIBSIZE); + t--; + /* perform KW operation: decrypt block */ + crypto_cipher_decrypt_one(child, (u8*)block, + (u8*)block); + + /* move pointer by tmp_nbytes in the SGL */ + crypto_kw_scatterlist_ff(&dst_walk, ldst, tmp_nbytes); + /* Copy block->R into place */ + scatterwalk_copychunks(block->R, &dst_walk, SEMIBSIZE, + true); + + tmp_nbytes -= SEMIBSIZE; + } + + /* we now start to operate on the dst SGL only */ + lsrc = dst; + ldst = dst; + } + + /* Perform authentication check */ + if (crypto_memneq("\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6", block->A, + SEMIBSIZE)) + ret = -EBADMSG; + + memzero_explicit(&block, sizeof(struct crypto_kw_block)); + + return ret; +} + +static int crypto_kw_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct crypto_blkcipher *tfm = desc->tfm; + struct crypto_kw_ctx *ctx = crypto_blkcipher_ctx(tfm); + struct crypto_cipher *child = ctx->child; + + unsigned long alignmask = max_t(unsigned long, SEMIBSIZE, + crypto_cipher_alignmask(child)); + unsigned int i; + + u8 blockbuf[sizeof(struct crypto_kw_block) + alignmask]; + struct crypto_kw_block *block = (struct crypto_kw_block *) + PTR_ALIGN(blockbuf + 0, alignmask + 1); + + u64 t = 1; + struct scatterlist *lsrc, *ldst; + + /* + * Require at least 2 semiblocks (note, the 3rd semiblock that is + * required by SP800-38F is the IV that occupies the first semiblock. + * This means that the dst memory must be one semiblock larger than src. + * Also ensure that the given data is aligned to semiblock. + */ + if (nbytes < (2 * SEMIBSIZE) || nbytes % SEMIBSIZE) + return -EINVAL; + + /* + * Place the predefined IV into block A -- for encrypt, the caller + * does not need to provide an IV, but he needs to fetch the final IV. + */ + memcpy(block->A, "\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6", SEMIBSIZE); + + /* + * src scatterlist is read-only. dst scatterlist is r/w. During the + * first loop, lsrc points to src and ldst to dst. For any + * subsequent round, the code operates on dst only. + */ + lsrc = src; + ldst = dst; + + for (i = 0; i < 6; i++) { + u8 tbe_buffer[SEMIBSIZE + alignmask]; + u8 *tbe = PTR_ALIGN(tbe_buffer + 0, alignmask + 1); + unsigned int tmp_nbytes = nbytes; + struct scatter_walk src_walk, dst_walk; + + scatterwalk_start(&src_walk, lsrc); + scatterwalk_start(&dst_walk, ldst); + + while (tmp_nbytes) { + /* get the source block */ + scatterwalk_copychunks(block->R, &src_walk, SEMIBSIZE, + false); + + /* perform KW operation: encrypt block */ + crypto_cipher_encrypt_one(child, (u8 *)block, + (u8 *)block); + /* perform KW operation: get counter as byte string */ + crypto_kw_cpu_to_be64(t, tbe); + /* perform KW operation: modify IV with counter */ + crypto_xor(block->A, tbe, SEMIBSIZE); + t++; + + /* Copy block->R into place */ + scatterwalk_copychunks(block->R, &dst_walk, SEMIBSIZE, + true); + + tmp_nbytes -= SEMIBSIZE; + } + + /* we now start to operate on the dst SGL only */ + lsrc = dst; + ldst = dst; + } + + /* establish the IV for the caller to pick up */ + memcpy(desc->info, block->A, SEMIBSIZE); + + memzero_explicit(&block, sizeof(struct crypto_kw_block)); + + return 0; +} + +static int crypto_kw_setkey(struct crypto_tfm *parent, const u8 *key, + unsigned int keylen) +{ + struct crypto_kw_ctx *ctx = crypto_tfm_ctx(parent); + struct crypto_cipher *child = ctx->child; + int err; + + crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_cipher_set_flags(child, crypto_tfm_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_cipher_setkey(child, key, keylen); + crypto_tfm_set_flags(parent, crypto_cipher_get_flags(child) & + CRYPTO_TFM_RES_MASK); + return err; +} + +static int crypto_kw_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); + struct crypto_spawn *spawn = crypto_instance_ctx(inst); + struct crypto_kw_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_cipher *cipher; + + cipher = crypto_spawn_cipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); + + ctx->child = cipher; + return 0; +} + +static void crypto_kw_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_kw_ctx *ctx = crypto_tfm_ctx(tfm); + + crypto_free_cipher(ctx->child); +} + +static struct crypto_instance *crypto_kw_alloc(struct rtattr **tb) +{ + struct crypto_instance *inst = NULL; + struct crypto_alg *alg = NULL; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER); + if (err) + return ERR_PTR(err); + + alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK); + if (IS_ERR(alg)) + return ERR_CAST(alg); + + inst = ERR_PTR(-EINVAL); + /* Section 5.1 requirement for KW */ + if (alg->cra_blocksize != sizeof(struct crypto_kw_block)) + goto err; + + inst = crypto_alloc_instance("kw", alg); + if (IS_ERR(inst)) + goto err; + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER; + inst->alg.cra_priority = alg->cra_priority; + inst->alg.cra_blocksize = SEMIBSIZE; + inst->alg.cra_alignmask = 0; + inst->alg.cra_type = &crypto_blkcipher_type; + inst->alg.cra_blkcipher.ivsize = SEMIBSIZE; + inst->alg.cra_blkcipher.min_keysize = alg->cra_cipher.cia_min_keysize; + inst->alg.cra_blkcipher.max_keysize = alg->cra_cipher.cia_max_keysize; + + inst->alg.cra_ctxsize = sizeof(struct crypto_kw_ctx); + + inst->alg.cra_init = crypto_kw_init_tfm; + inst->alg.cra_exit = crypto_kw_exit_tfm; + + inst->alg.cra_blkcipher.setkey = crypto_kw_setkey; + inst->alg.cra_blkcipher.encrypt = crypto_kw_encrypt; + inst->alg.cra_blkcipher.decrypt = crypto_kw_decrypt; + +err: + crypto_mod_put(alg); + return inst; +} + +static void crypto_kw_free(struct crypto_instance *inst) +{ + crypto_drop_spawn(crypto_instance_ctx(inst)); + kfree(inst); +} + +static struct crypto_template crypto_kw_tmpl = { + .name = "kw", + .alloc = crypto_kw_alloc, + .free = crypto_kw_free, + .module = THIS_MODULE, +}; + +static int __init crypto_kw_init(void) +{ + return crypto_register_template(&crypto_kw_tmpl); +} + +static void __exit crypto_kw_exit(void) +{ + crypto_unregister_template(&crypto_kw_tmpl); +} + +module_init(crypto_kw_init); +module_exit(crypto_kw_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>"); +MODULE_DESCRIPTION("Key Wrapping (RFC3394 / NIST SP800-38F)"); +MODULE_ALIAS_CRYPTO("kw"); diff --git a/crypto/rsa.c b/crypto/rsa.c index 466003e1a8cf..1093e041db03 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -97,24 +97,21 @@ static int rsa_enc(struct akcipher_request *req) goto err_free_c; } - m = mpi_read_raw_data(req->src, req->src_len); - if (!m) { - ret = -ENOMEM; + ret = -ENOMEM; + m = mpi_read_raw_from_sgl(req->src, req->src_len); + if (!m) goto err_free_c; - } ret = _rsa_enc(pkey, c, m); if (ret) goto err_free_m; - ret = mpi_read_buffer(c, req->dst, req->dst_len, &req->dst_len, &sign); + ret = mpi_write_to_sgl(c, req->dst, &req->dst_len, &sign); if (ret) goto err_free_m; - if (sign < 0) { + if (sign < 0) ret = -EBADMSG; - goto err_free_m; - } err_free_m: mpi_free(m); @@ -145,25 +142,21 @@ static int rsa_dec(struct akcipher_request *req) goto err_free_m; } - c = mpi_read_raw_data(req->src, req->src_len); - if (!c) { - ret = -ENOMEM; + ret = -ENOMEM; + c = mpi_read_raw_from_sgl(req->src, req->src_len); + if (!c) goto err_free_m; - } ret = _rsa_dec(pkey, m, c); if (ret) goto err_free_c; - ret = mpi_read_buffer(m, req->dst, req->dst_len, &req->dst_len, &sign); + ret = mpi_write_to_sgl(m, req->dst, &req->dst_len, &sign); if (ret) goto err_free_c; - if (sign < 0) { + if (sign < 0) ret = -EBADMSG; - goto err_free_c; - } - err_free_c: mpi_free(c); err_free_m: @@ -193,24 +186,21 @@ static int rsa_sign(struct akcipher_request *req) goto err_free_s; } - m = mpi_read_raw_data(req->src, req->src_len); - if (!m) { - ret = -ENOMEM; + ret = -ENOMEM; + m = mpi_read_raw_from_sgl(req->src, req->src_len); + if (!m) goto err_free_s; - } ret = _rsa_sign(pkey, s, m); if (ret) goto err_free_m; - ret = mpi_read_buffer(s, req->dst, req->dst_len, &req->dst_len, &sign); + ret = mpi_write_to_sgl(s, req->dst, &req->dst_len, &sign); if (ret) goto err_free_m; - if (sign < 0) { + if (sign < 0) ret = -EBADMSG; - goto err_free_m; - } err_free_m: mpi_free(m); @@ -241,7 +231,8 @@ static int rsa_verify(struct akcipher_request *req) goto err_free_m; } - s = mpi_read_raw_data(req->src, req->src_len); + ret = -ENOMEM; + s = mpi_read_raw_from_sgl(req->src, req->src_len); if (!s) { ret = -ENOMEM; goto err_free_m; @@ -251,14 +242,12 @@ static int rsa_verify(struct akcipher_request *req) if (ret) goto err_free_s; - ret = mpi_read_buffer(m, req->dst, req->dst_len, &req->dst_len, &sign); + ret = mpi_write_to_sgl(m, req->dst, &req->dst_len, &sign); if (ret) goto err_free_s; - if (sign < 0) { + if (sign < 0) ret = -EBADMSG; - goto err_free_s; - } err_free_s: mpi_free(s); @@ -282,13 +271,13 @@ static int rsa_check_key_length(unsigned int len) return -EINVAL; } -static int rsa_setkey(struct crypto_akcipher *tfm, const void *key, - unsigned int keylen) +static int rsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, + unsigned int keylen) { struct rsa_key *pkey = akcipher_tfm_ctx(tfm); int ret; - ret = rsa_parse_key(pkey, key, keylen); + ret = rsa_parse_pub_key(pkey, key, keylen); if (ret) return ret; @@ -299,6 +288,30 @@ static int rsa_setkey(struct crypto_akcipher *tfm, const void *key, return ret; } +static int rsa_set_priv_key(struct crypto_akcipher *tfm, const void *key, + unsigned int keylen) +{ + struct rsa_key *pkey = akcipher_tfm_ctx(tfm); + int ret; + + ret = rsa_parse_priv_key(pkey, key, keylen); + if (ret) + return ret; + + if (rsa_check_key_length(mpi_get_size(pkey->n) << 3)) { + rsa_free_key(pkey); + ret = -EINVAL; + } + return ret; +} + +static int rsa_max_size(struct crypto_akcipher *tfm) +{ + struct rsa_key *pkey = akcipher_tfm_ctx(tfm); + + return pkey->n ? mpi_get_size(pkey->n) : -EINVAL; +} + static void rsa_exit_tfm(struct crypto_akcipher *tfm) { struct rsa_key *pkey = akcipher_tfm_ctx(tfm); @@ -311,7 +324,9 @@ static struct akcipher_alg rsa = { .decrypt = rsa_dec, .sign = rsa_sign, .verify = rsa_verify, - .setkey = rsa_setkey, + .set_priv_key = rsa_set_priv_key, + .set_pub_key = rsa_set_pub_key, + .max_size = rsa_max_size, .exit = rsa_exit_tfm, .base = { .cra_name = "rsa", diff --git a/crypto/rsa_helper.c b/crypto/rsa_helper.c index 8d96ce969b44..d226f48d0907 100644 --- a/crypto/rsa_helper.c +++ b/crypto/rsa_helper.c @@ -15,7 +15,8 @@ #include <linux/err.h> #include <linux/fips.h> #include <crypto/internal/rsa.h> -#include "rsakey-asn1.h" +#include "rsapubkey-asn1.h" +#include "rsaprivkey-asn1.h" int rsa_get_n(void *context, size_t hdrlen, unsigned char tag, const void *value, size_t vlen) @@ -94,8 +95,8 @@ void rsa_free_key(struct rsa_key *key) EXPORT_SYMBOL_GPL(rsa_free_key); /** - * rsa_parse_key() - extracts an rsa key from BER encoded buffer - * and stores it in the provided struct rsa_key + * rsa_parse_pub_key() - extracts an rsa public key from BER encoded buffer + * and stores it in the provided struct rsa_key * * @rsa_key: struct rsa_key key representation * @key: key in BER format @@ -103,13 +104,13 @@ EXPORT_SYMBOL_GPL(rsa_free_key); * * Return: 0 on success or error code in case of error */ -int rsa_parse_key(struct rsa_key *rsa_key, const void *key, - unsigned int key_len) +int rsa_parse_pub_key(struct rsa_key *rsa_key, const void *key, + unsigned int key_len) { int ret; free_mpis(rsa_key); - ret = asn1_ber_decoder(&rsakey_decoder, rsa_key, key, key_len); + ret = asn1_ber_decoder(&rsapubkey_decoder, rsa_key, key, key_len); if (ret < 0) goto error; @@ -118,4 +119,31 @@ error: free_mpis(rsa_key); return ret; } -EXPORT_SYMBOL_GPL(rsa_parse_key); +EXPORT_SYMBOL_GPL(rsa_parse_pub_key); + +/** + * rsa_parse_pub_key() - extracts an rsa private key from BER encoded buffer + * and stores it in the provided struct rsa_key + * + * @rsa_key: struct rsa_key key representation + * @key: key in BER format + * @key_len: length of key + * + * Return: 0 on success or error code in case of error + */ +int rsa_parse_priv_key(struct rsa_key *rsa_key, const void *key, + unsigned int key_len) +{ + int ret; + + free_mpis(rsa_key); + ret = asn1_ber_decoder(&rsaprivkey_decoder, rsa_key, key, key_len); + if (ret < 0) + goto error; + + return 0; +error: + free_mpis(rsa_key); + return ret; +} +EXPORT_SYMBOL_GPL(rsa_parse_priv_key); diff --git a/crypto/rsakey.asn1 b/crypto/rsakey.asn1 deleted file mode 100644 index 3c7b5df7b428..000000000000 --- a/crypto/rsakey.asn1 +++ /dev/null @@ -1,5 +0,0 @@ -RsaKey ::= SEQUENCE { - n INTEGER ({ rsa_get_n }), - e INTEGER ({ rsa_get_e }), - d INTEGER ({ rsa_get_d }) -} diff --git a/crypto/rsaprivkey.asn1 b/crypto/rsaprivkey.asn1 new file mode 100644 index 000000000000..731aea5edb0c --- /dev/null +++ b/crypto/rsaprivkey.asn1 @@ -0,0 +1,11 @@ +RsaPrivKey ::= SEQUENCE { + version INTEGER, + n INTEGER ({ rsa_get_n }), + e INTEGER ({ rsa_get_e }), + d INTEGER ({ rsa_get_d }), + prime1 INTEGER, + prime2 INTEGER, + exponent1 INTEGER, + exponent2 INTEGER, + coefficient INTEGER +} diff --git a/crypto/rsapubkey.asn1 b/crypto/rsapubkey.asn1 new file mode 100644 index 000000000000..725498e461d2 --- /dev/null +++ b/crypto/rsapubkey.asn1 @@ -0,0 +1,4 @@ +RsaPubKey ::= SEQUENCE { + n INTEGER ({ rsa_get_n }), + e INTEGER ({ rsa_get_e }) +} diff --git a/crypto/skcipher.c b/crypto/skcipher.c index dd5fc1bf6447..7591928be7ca 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -91,7 +91,7 @@ static void crypto_exit_skcipher_ops_blkcipher(struct crypto_tfm *tfm) crypto_free_blkcipher(*ctx); } -int crypto_init_skcipher_ops_blkcipher(struct crypto_tfm *tfm) +static int crypto_init_skcipher_ops_blkcipher(struct crypto_tfm *tfm) { struct crypto_alg *calg = tfm->__crt_alg; struct crypto_skcipher *skcipher = __crypto_skcipher_cast(tfm);< |