From patchwork Tue Jun 13 09:38:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herbert Xu X-Patchwork-Id: 692187 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 96870C88CB7 for ; Tue, 13 Jun 2023 09:38:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239409AbjFMJif (ORCPT ); Tue, 13 Jun 2023 05:38:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55904 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238497AbjFMJid (ORCPT ); Tue, 13 Jun 2023 05:38:33 -0400 Received: from 167-179-156-38.a7b39c.syd.nbn.aussiebb.net (167-179-156-38.a7b39c.syd.nbn.aussiebb.net [167.179.156.38]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5E0AFEC; Tue, 13 Jun 2023 02:38:30 -0700 (PDT) Received: from loth.rohan.me.apana.org.au ([192.168.167.2]) by formenos.hmeau.com with smtp (Exim 4.94.2 #2 (Debian)) id 1q90Tb-002LQK-6x; Tue, 13 Jun 2023 17:38:12 +0800 Received: by loth.rohan.me.apana.org.au (sSMTP sendmail emulation); Tue, 13 Jun 2023 17:38:11 +0800 From: "Herbert Xu" Date: Tue, 13 Jun 2023 17:38:11 +0800 Subject: [PATCH 2/5] crypto: dsa - Add interface for sign/verify References: To: Linus Torvalds , Roberto Sassu , David Howells , Eric Biggers , Stefan Berger , Mimi Zohar , dmitry.kasatkin@gmail.com, Jarkko Sakkinen , Ard Biesheuvel , keyrings@vger.kernel.org, Linux Crypto Mailing List Message-Id: Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Split out the sign/verify functionality from the existing akcipher interface. Most algorithms in akcipher either support encryption and decryption, or signing and verify. Only one supports both. As a signature algorithm may not support encryption at all, these two should be spearated. For now dsa is simply a wrapper around akcipher as all algorithms remain unchanged. This is a first step and allows users to start allocating dsa instead of akcipher. Signed-off-by: Herbert Xu --- crypto/Kconfig | 10 ++ crypto/Makefile | 1 crypto/akcipher.c | 53 +++++++++----- crypto/dsa.c | 159 ++++++++++++++++++++++++++++++++++++++++++ crypto/internal.h | 20 +++++ include/crypto/dsa.h | 140 ++++++++++++++++++++++++++++++++++++ include/crypto/internal/dsa.h | 17 ++++ include/linux/crypto.h | 3 8 files changed, 385 insertions(+), 18 deletions(-) diff --git a/crypto/Kconfig b/crypto/Kconfig index 8b8bb97d1d77..c3c7e1108c32 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -72,6 +72,15 @@ config CRYPTO_AEAD2 tristate select CRYPTO_ALGAPI2 +config CRYPTO_DSA + tristate + select CRYPTO_DSA2 + select CRYPTO_ALGAPI + +config CRYPTO_DSA2 + tristate + select CRYPTO_ALGAPI2 + config CRYPTO_SKCIPHER tristate select CRYPTO_SKCIPHER2 @@ -143,6 +152,7 @@ config CRYPTO_MANAGER2 select CRYPTO_ACOMP2 select CRYPTO_AEAD2 select CRYPTO_AKCIPHER2 + select CRYPTO_DSA2 select CRYPTO_HASH2 select CRYPTO_KPP2 select CRYPTO_RNG2 diff --git a/crypto/Makefile b/crypto/Makefile index 155ab671a1b4..9bdb0af75f73 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -25,6 +25,7 @@ crypto_hash-y += shash.o obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o obj-$(CONFIG_CRYPTO_AKCIPHER2) += akcipher.o +obj-$(CONFIG_CRYPTO_DSA2) += dsa.o obj-$(CONFIG_CRYPTO_KPP2) += kpp.o dh_generic-y := dh.o diff --git a/crypto/akcipher.c b/crypto/akcipher.c index 2d10b58c4010..76ab150b5df4 100644 --- a/crypto/akcipher.c +++ b/crypto/akcipher.c @@ -18,18 +18,7 @@ #include "internal.h" -struct crypto_akcipher_sync_data { - struct crypto_akcipher *tfm; - const void *src; - void *dst; - unsigned int slen; - unsigned int dlen; - - struct akcipher_request *req; - struct crypto_wait cwait; - struct scatterlist sg; - u8 *buf; -}; +#define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000e static int __maybe_unused crypto_akcipher_report( struct sk_buff *skb, struct crypto_alg *alg) @@ -119,7 +108,7 @@ static const struct crypto_type crypto_akcipher_type = { .report_stat = crypto_akcipher_report_stat, #endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, - .maskset = CRYPTO_ALG_TYPE_MASK, + .maskset = CRYPTO_ALG_TYPE_AHASH_MASK, .type = CRYPTO_ALG_TYPE_AKCIPHER, .tfmsize = offsetof(struct crypto_akcipher, base), }; @@ -200,7 +189,7 @@ int akcipher_register_instance(struct crypto_template *tmpl, } EXPORT_SYMBOL_GPL(akcipher_register_instance); -static int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data) +int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data) { unsigned int reqsize = crypto_akcipher_reqsize(data->tfm); unsigned int mlen = max(data->slen, data->dlen); @@ -223,7 +212,7 @@ static int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data) data->buf = buf; memcpy(buf, data->src, data->slen); - sg = &data->sg; + sg = data->sg; sg_init_one(sg, buf, mlen); akcipher_request_set_crypt(req, sg, sg, data->slen, data->dlen); @@ -233,9 +222,9 @@ static int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data) return 0; } +EXPORT_SYMBOL_GPL(crypto_akcipher_sync_prep); -static int crypto_akcipher_sync_post(struct crypto_akcipher_sync_data *data, - int err) +int crypto_akcipher_sync_post(struct crypto_akcipher_sync_data *data, int err) { err = crypto_wait_req(err, &data->cwait); memcpy(data->dst, data->buf, data->dlen); @@ -243,6 +232,7 @@ static int crypto_akcipher_sync_post(struct crypto_akcipher_sync_data *data, kfree_sensitive(data->req); return err; } +EXPORT_SYMBOL_GPL(crypto_akcipher_sync_post); int crypto_akcipher_sync_encrypt(struct crypto_akcipher *tfm, const void *src, unsigned int slen, @@ -281,5 +271,34 @@ int crypto_akcipher_sync_decrypt(struct crypto_akcipher *tfm, } EXPORT_SYMBOL_GPL(crypto_akcipher_sync_decrypt); +static void crypto_exit_akcipher_ops_dsa(struct crypto_tfm *tfm) +{ + struct crypto_akcipher **ctx = crypto_tfm_ctx(tfm); + + crypto_free_akcipher(*ctx); +} + +int crypto_init_akcipher_ops_dsa(struct crypto_tfm *tfm) +{ + struct crypto_akcipher **ctx = crypto_tfm_ctx(tfm); + struct crypto_alg *calg = tfm->__crt_alg; + struct crypto_akcipher *akcipher; + + if (!crypto_mod_get(calg)) + return -EAGAIN; + + akcipher = crypto_create_tfm(calg, &crypto_akcipher_type); + if (IS_ERR(akcipher)) { + crypto_mod_put(calg); + return PTR_ERR(akcipher); + } + + *ctx = akcipher; + tfm->exit = crypto_exit_akcipher_ops_dsa; + + return 0; +} +EXPORT_SYMBOL_GPL(crypto_init_akcipher_ops_dsa); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic public key cipher type"); diff --git a/crypto/dsa.c b/crypto/dsa.c new file mode 100644 index 000000000000..36ea2d0828b1 --- /dev/null +++ b/crypto/dsa.c @@ -0,0 +1,159 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Digital Signature Algorithm + * + * Copyright (c) 2023 Herbert Xu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +#define CRYPTO_ALG_TYPE_DSA_MASK 0x0000000e + +static const struct crypto_type crypto_dsa_type; + +static inline struct crypto_dsa *__crypto_dsa_tfm(struct crypto_tfm *tfm) +{ + return container_of(tfm, struct crypto_dsa, base); +} + +static int crypto_dsa_init_tfm(struct crypto_tfm *tfm) +{ + if (tfm->__crt_alg->cra_type != &crypto_dsa_type) + return crypto_init_akcipher_ops_dsa(tfm); + + return 0; +} + +static void __maybe_unused crypto_dsa_show(struct seq_file *m, + struct crypto_alg *alg) +{ + seq_puts(m, "type : dsa\n"); +} + +static int __maybe_unused crypto_dsa_report(struct sk_buff *skb, + struct crypto_alg *alg) +{ + struct crypto_report_akcipher rdsa = {}; + + strscpy(rdsa.type, "dsa", sizeof(rdsa.type)); + + return nla_put(skb, CRYPTOCFGA_REPORT_AKCIPHER, sizeof(rdsa), &rdsa); +} + +static int __maybe_unused crypto_dsa_report_stat(struct sk_buff *skb, + struct crypto_alg *alg) +{ + struct crypto_stat_akcipher rdsa = {}; + + strscpy(rdsa.type, "dsa", sizeof(rdsa.type)); + + return nla_put(skb, CRYPTOCFGA_STAT_AKCIPHER, sizeof(rdsa), &rdsa); +} + +static const struct crypto_type crypto_dsa_type = { + .extsize = crypto_alg_extsize, + .init_tfm = crypto_dsa_init_tfm, +#ifdef CONFIG_PROC_FS + .show = crypto_dsa_show, +#endif +#if IS_ENABLED(CONFIG_CRYPTO_USER) + .report = crypto_dsa_report, +#endif +#ifdef CONFIG_CRYPTO_STATS + .report_stat = crypto_dsa_report_stat, +#endif + .maskclear = ~CRYPTO_ALG_TYPE_MASK, + .maskset = CRYPTO_ALG_TYPE_DSA_MASK, + .type = CRYPTO_ALG_TYPE_DSA, + .tfmsize = offsetof(struct crypto_dsa, base), +}; + +struct crypto_dsa *crypto_alloc_dsa(const char *alg_name, u32 type, u32 mask) +{ + return crypto_alloc_tfm(alg_name, &crypto_dsa_type, type, mask); +} +EXPORT_SYMBOL_GPL(crypto_alloc_dsa); + +int crypto_dsa_maxsize(struct crypto_dsa *tfm) +{ + struct crypto_akcipher **ctx = crypto_dsa_ctx(tfm); + + return crypto_akcipher_maxsize(*ctx); +} +EXPORT_SYMBOL_GPL(crypto_dsa_maxsize); + +int crypto_dsa_sign(struct crypto_dsa *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + struct crypto_akcipher **ctx = crypto_dsa_ctx(tfm); + struct crypto_akcipher_sync_data data = { + .tfm = *ctx, + .src = src, + .dst = dst, + .slen = slen, + .dlen = dlen, + }; + + return crypto_akcipher_sync_prep(&data) ?: + crypto_akcipher_sync_post(&data, + crypto_akcipher_sign(data.req)); +} +EXPORT_SYMBOL_GPL(crypto_dsa_sign); + +int crypto_dsa_verify(struct crypto_dsa *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen) +{ + struct crypto_akcipher **ctx = crypto_dsa_ctx(tfm); + struct crypto_akcipher_sync_data data = { + .tfm = *ctx, + .src = src, + .slen = slen, + .dlen = dlen, + }; + int err; + + err = crypto_akcipher_sync_prep(&data); + if (err) + return err; + + sg_init_table(data.sg, 2); + sg_set_buf(&data.sg[0], src, slen); + sg_set_buf(&data.sg[1], digest, dlen); + + return crypto_akcipher_sync_post(&data, + crypto_akcipher_verify(data.req)); +} +EXPORT_SYMBOL_GPL(crypto_dsa_verify); + +int crypto_dsa_set_pubkey(struct crypto_dsa *tfm, + const void *key, unsigned int keylen) +{ + struct crypto_akcipher **ctx = crypto_dsa_ctx(tfm); + + return crypto_akcipher_set_pub_key(*ctx, key, keylen); +} +EXPORT_SYMBOL_GPL(crypto_dsa_set_pubkey); + +int crypto_dsa_set_privkey(struct crypto_dsa *tfm, + const void *key, unsigned int keylen) +{ + struct crypto_akcipher **ctx = crypto_dsa_ctx(tfm); + + return crypto_akcipher_set_priv_key(*ctx, key, keylen); +} +EXPORT_SYMBOL_GPL(crypto_dsa_set_privkey); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Digital Signature Algorithms"); diff --git a/crypto/internal.h b/crypto/internal.h index 8dd746b1130b..024c2c795f59 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -18,9 +18,12 @@ #include #include #include +#include #include #include +struct akcipher_request; +struct crypto_akcipher; struct crypto_instance; struct crypto_template; @@ -32,6 +35,19 @@ struct crypto_larval { bool test_started; }; +struct crypto_akcipher_sync_data { + struct crypto_akcipher *tfm; + const void *src; + void *dst; + unsigned int slen; + unsigned int dlen; + + struct akcipher_request *req; + struct crypto_wait cwait; + struct scatterlist sg[2]; + u8 *buf; +}; + enum { CRYPTOA_UNSPEC, CRYPTOA_ALG, @@ -109,6 +125,10 @@ void *crypto_create_tfm_node(struct crypto_alg *alg, void *crypto_clone_tfm(const struct crypto_type *frontend, struct crypto_tfm *otfm); +int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data); +int crypto_akcipher_sync_post(struct crypto_akcipher_sync_data *data, int err); +int crypto_init_akcipher_ops_dsa(struct crypto_tfm *tfm); + static inline void *crypto_create_tfm(struct crypto_alg *alg, const struct crypto_type *frontend) { diff --git a/include/crypto/dsa.h b/include/crypto/dsa.h new file mode 100644 index 000000000000..98ce39e9d054 --- /dev/null +++ b/include/crypto/dsa.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Digital Signature Algorithm + * + * Copyright (c) 2023 Herbert Xu + */ +#ifndef _CRYPTO_DSA_H +#define _CRYPTO_DSA_H + +#include + +/** + * struct crypto_dsa - user-instantiated objects which encapsulate + * algorithms and core processing logic + * + * @base: Common crypto API algorithm data structure + */ +struct crypto_dsa { + struct crypto_tfm base; +}; + +/** + * DOC: Generic Digital Signature API + * + * The Digital Signature API is used with the algorithms of type + * CRYPTO_ALG_TYPE_DSA (listed as type "dsa" in /proc/crypto) + */ + +/** + * crypto_alloc_dsa() - allocate DSA tfm handle + * @alg_name: is the cra_name / name or cra_driver_name / driver name of the + * signing algorithm e.g. "ecdsa" + * @type: specifies the type of the algorithm + * @mask: specifies the mask for the algorithm + * + * Allocate a handle for digital signature algorithm. The returned struct + * crypto_dsa is the handle that is required for any subsequent + * API invocation for signature operations. + * + * Return: allocated handle in case of success; IS_ERR() is true in case + * of an error, PTR_ERR() returns the error code. + */ +struct crypto_dsa *crypto_alloc_dsa(const char *alg_name, u32 type, u32 mask); + +static inline struct crypto_tfm *crypto_dsa_tfm(struct crypto_dsa *tfm) +{ + return &tfm->base; +} + +/** + * crypto_free_dsa() - free DSA tfm handle + * + * @tfm: DSA tfm handle allocated with crypto_alloc_dsa() + * + * If @tfm is a NULL or error pointer, this function does nothing. + */ +static inline void crypto_free_dsa(struct crypto_dsa *tfm) +{ + crypto_destroy_tfm(tfm, crypto_dsa_tfm(tfm)); +} + +/** + * crypto_dsa_maxsize() - Get len for output buffer + * + * Function returns the dest buffer size required for a given key. + * Function assumes that the key is already set in the transformation. If this + * function is called without a setkey or with a failed setkey, you will end up + * in a NULL dereference. + * + * @tfm: DSA tfm handle allocated with crypto_alloc_dsa() + */ +int crypto_dsa_maxsize(struct crypto_dsa *tfm); + +/** + * crypto_dsa_sign() - Invoke signing operation + * + * Function invokes the specific signing operation for a given DSA + * + * @tfm: DSA tfm handle allocated with crypto_alloc_dsa() + * @src: source buffer + * @slen: source length + * @dst: destinatino obuffer + * @dlen: destination length + * + * Return: zero on success; error code in case of error + */ +int crypto_dsa_sign(struct crypto_dsa *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen); + +/** + * crypto_dsa_verify() - Invoke signature verification + * + * Function invokes the specific signature verification operation + * for a given DSA. + * + * @tfm: DSA tfm handle allocated with crypto_alloc_dsa() + * @src: source buffer + * @slen: source length + * @digest: digest + * @dlen: digest length + * + * Return: zero on verification success; error code in case of error. + */ +int crypto_dsa_verify(struct crypto_dsa *tfm, + const void *src, unsigned int slen, + const void *digest, unsigned int dlen); + +/** + * crypto_dsa_set_pubkey() - Invoke set public key operation + * + * Function invokes the algorithm specific set key function, which knows + * how to decode and interpret the encoded key and parameters + * + * @tfm: tfm handle + * @key: BER encoded public key, algo OID, paramlen, BER encoded + * parameters + * @keylen: length of the key (not including other data) + * + * Return: zero on success; error code in case of error + */ +int crypto_dsa_set_pubkey(struct crypto_dsa *tfm, + const void *key, unsigned int keylen); + +/** + * crypto_dsa_set_privkey() - Invoke set private key operation + * + * Function invokes the algorithm specific set key function, which knows + * how to decode and interpret the encoded key and parameters + * + * @tfm: tfm handle + * @key: BER encoded private key, algo OID, paramlen, BER encoded + * parameters + * @keylen: length of the key (not including other data) + * + * Return: zero on success; error code in case of error + */ +int crypto_dsa_set_privkey(struct crypto_dsa *tfm, + const void *key, unsigned int keylen); +#endif diff --git a/include/crypto/internal/dsa.h b/include/crypto/internal/dsa.h new file mode 100644 index 000000000000..5586551693e4 --- /dev/null +++ b/include/crypto/internal/dsa.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Digital Signature Algorithm + * + * Copyright (c) 2023 Herbert Xu + */ +#ifndef _CRYPTO_INTERNAL_DSA_H +#define _CRYPTO_INTERNAL_DSA_H + +#include +#include + +static inline void *crypto_dsa_ctx(struct crypto_dsa *tfm) +{ + return crypto_tfm_ctx(&tfm->base); +} +#endif diff --git a/include/linux/crypto.h b/include/linux/crypto.h index fa310ac1db59..fbf3139c11f0 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -25,11 +25,12 @@ #define CRYPTO_ALG_TYPE_COMPRESS 0x00000002 #define CRYPTO_ALG_TYPE_AEAD 0x00000003 #define CRYPTO_ALG_TYPE_SKCIPHER 0x00000005 +#define CRYPTO_ALG_TYPE_AKCIPHER 0x00000006 +#define CRYPTO_ALG_TYPE_DSA 0x00000007 #define CRYPTO_ALG_TYPE_KPP 0x00000008 #define CRYPTO_ALG_TYPE_ACOMPRESS 0x0000000a #define CRYPTO_ALG_TYPE_SCOMPRESS 0x0000000b #define CRYPTO_ALG_TYPE_RNG 0x0000000c -#define CRYPTO_ALG_TYPE_AKCIPHER 0x0000000d #define CRYPTO_ALG_TYPE_HASH 0x0000000e #define CRYPTO_ALG_TYPE_SHASH 0x0000000e #define CRYPTO_ALG_TYPE_AHASH 0x0000000f From patchwork Tue Jun 13 09:38:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herbert Xu X-Patchwork-Id: 692188 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D3A1FC7EE29 for ; Tue, 13 Jun 2023 09:38:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234253AbjFMJid (ORCPT ); Tue, 13 Jun 2023 05:38:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55894 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239355AbjFMJib (ORCPT ); Tue, 13 Jun 2023 05:38:31 -0400 Received: from 167-179-156-38.a7b39c.syd.nbn.aussiebb.net (167-179-156-38.a7b39c.syd.nbn.aussiebb.net [167.179.156.38]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6EE0D10D9; Tue, 13 Jun 2023 02:38:30 -0700 (PDT) Received: from loth.rohan.me.apana.org.au ([192.168.167.2]) by formenos.hmeau.com with smtp (Exim 4.94.2 #2 (Debian)) id 1q90Td-002LQV-Ci; Tue, 13 Jun 2023 17:38:14 +0800 Received: by loth.rohan.me.apana.org.au (sSMTP sendmail emulation); Tue, 13 Jun 2023 17:38:13 +0800 From: "Herbert Xu" Date: Tue, 13 Jun 2023 17:38:13 +0800 Subject: [PATCH 3/5] KEYS: Add forward declaration in asymmetric-parser.h References: To: Linus Torvalds , Roberto Sassu , David Howells , Eric Biggers , Stefan Berger , Mimi Zohar , dmitry.kasatkin@gmail.com, Jarkko Sakkinen , Ard Biesheuvel , keyrings@vger.kernel.org, Linux Crypto Mailing List Message-Id: Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Add forward declaration for struct key_preparsed_payload so that this header file is self-contained. Signed-off-by: Herbert Xu --- include/keys/asymmetric-parser.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/keys/asymmetric-parser.h b/include/keys/asymmetric-parser.h index c47dc5405f79..516a3f51179e 100644 --- a/include/keys/asymmetric-parser.h +++ b/include/keys/asymmetric-parser.h @@ -10,6 +10,8 @@ #ifndef _KEYS_ASYMMETRIC_PARSER_H #define _KEYS_ASYMMETRIC_PARSER_H +struct key_preparsed_payload; + /* * Key data parser. Called during key instantiation. */ From patchwork Tue Jun 13 09:38:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herbert Xu X-Patchwork-Id: 692186 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 037F9C88CB4 for ; Tue, 13 Jun 2023 09:38:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240450AbjFMJim (ORCPT ); Tue, 13 Jun 2023 05:38:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55974 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238497AbjFMJih (ORCPT ); Tue, 13 Jun 2023 05:38:37 -0400 Received: from 167-179-156-38.a7b39c.syd.nbn.aussiebb.net (167-179-156-38.a7b39c.syd.nbn.aussiebb.net [167.179.156.38]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 33CEB107; Tue, 13 Jun 2023 02:38:34 -0700 (PDT) Received: from loth.rohan.me.apana.org.au ([192.168.167.2]) by formenos.hmeau.com with smtp (Exim 4.94.2 #2 (Debian)) id 1q90Th-002LRI-JG; Tue, 13 Jun 2023 17:38:18 +0800 Received: by loth.rohan.me.apana.org.au (sSMTP sendmail emulation); Tue, 13 Jun 2023 17:38:17 +0800 From: "Herbert Xu" Date: Tue, 13 Jun 2023 17:38:17 +0800 Subject: [PATCH 5/5] KEYS: asymmetric: Use new crypto interface without scatterlists References: To: Linus Torvalds , Roberto Sassu , David Howells , Eric Biggers , Stefan Berger , Mimi Zohar , dmitry.kasatkin@gmail.com, Jarkko Sakkinen , Ard Biesheuvel , keyrings@vger.kernel.org, Linux Crypto Mailing List Message-Id: Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Use the new akcipher and dsa interfaces which no longer have scatterlists in them. Signed-off-by: Herbert Xu --- crypto/asymmetric_keys/public_key.c | 238 +++++++++++++++++++++--------------- 1 file changed, 139 insertions(+), 99 deletions(-) diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index c795a12a3599..e4161e2e8cc6 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -8,16 +8,17 @@ */ #define pr_fmt(fmt) "PKEY: "fmt -#include -#include +#include +#include +#include +#include +#include +#include #include -#include +#include #include -#include -#include -#include -#include -#include +#include +#include MODULE_DESCRIPTION("In-software asymmetric public-key subtype"); MODULE_AUTHOR("Red Hat, Inc."); @@ -65,10 +66,13 @@ static void public_key_destroy(void *payload0, void *payload3) static int software_key_determine_akcipher(const struct public_key *pkey, const char *encoding, const char *hash_algo, - char alg_name[CRYPTO_MAX_ALG_NAME]) + char alg_name[CRYPTO_MAX_ALG_NAME], bool *dsa, + enum kernel_pkey_operation op) { int n; + *dsa = true; + if (!encoding) return -EINVAL; @@ -77,14 +81,18 @@ software_key_determine_akcipher(const struct public_key *pkey, * RSA signatures usually use EMSA-PKCS1-1_5 [RFC3447 sec 8.2]. */ if (strcmp(encoding, "pkcs1") == 0) { - if (!hash_algo) + if (!hash_algo) { + *dsa = false; n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s)", pkey->pkey_algo); - else + } else { + *dsa = op == kernel_pkey_sign || + op == kernel_pkey_verify; n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, "pkcs1pad(%s,%s)", pkey->pkey_algo, hash_algo); + } return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0; } if (strcmp(encoding, "raw") != 0) @@ -95,6 +103,7 @@ software_key_determine_akcipher(const struct public_key *pkey, */ if (hash_algo) return -EINVAL; + *dsa = false; } else if (strncmp(pkey->pkey_algo, "ecdsa", 5) == 0) { if (strcmp(encoding, "x962") != 0) return -EINVAL; @@ -152,37 +161,70 @@ static int software_key_query(const struct kernel_pkey_params *params, struct crypto_akcipher *tfm; struct public_key *pkey = params->key->payload.data[asym_crypto]; char alg_name[CRYPTO_MAX_ALG_NAME]; + struct crypto_dsa *dsa; u8 *key, *ptr; int ret, len; + bool isdsa; ret = software_key_determine_akcipher(pkey, params->encoding, - params->hash_algo, alg_name); + params->hash_algo, alg_name, + &isdsa, kernel_pkey_sign); if (ret < 0) return ret; - tfm = crypto_alloc_akcipher(alg_name, 0, 0); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); - - ret = -ENOMEM; key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen, GFP_KERNEL); if (!key) - goto error_free_tfm; + return -ENOMEM; + memcpy(key, pkey->key, pkey->keylen); ptr = key + pkey->keylen; ptr = pkey_pack_u32(ptr, pkey->algo); ptr = pkey_pack_u32(ptr, pkey->paramlen); memcpy(ptr, pkey->params, pkey->paramlen); - if (pkey->key_is_private) - ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen); - else - ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen); - if (ret < 0) - goto error_free_key; + if (isdsa) { + dsa = crypto_alloc_dsa(alg_name, 0, 0); + if (IS_ERR(dsa)) + goto error_free_key; + + if (pkey->key_is_private) + ret = crypto_dsa_set_privkey(dsa, key, pkey->keylen); + else + ret = crypto_dsa_set_pubkey(dsa, key, pkey->keylen); + if (ret < 0) + goto error_free_tfm; + + len = crypto_dsa_maxsize(dsa); + + info->supported_ops = KEYCTL_SUPPORTS_VERIFY; + if (pkey->key_is_private) + info->supported_ops |= KEYCTL_SUPPORTS_SIGN; + + if (strcmp(params->encoding, "pkcs1") == 0) { + info->supported_ops |= KEYCTL_SUPPORTS_ENCRYPT; + if (pkey->key_is_private) + info->supported_ops |= KEYCTL_SUPPORTS_DECRYPT; + } + } else { + tfm = crypto_alloc_akcipher(alg_name, 0, 0); + if (IS_ERR(tfm)) + goto error_free_key; + + if (pkey->key_is_private) + ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen); + else + ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen); + if (ret < 0) + goto error_free_tfm; + + len = crypto_akcipher_maxsize(tfm); + + info->supported_ops = KEYCTL_SUPPORTS_ENCRYPT; + if (pkey->key_is_private) + info->supported_ops |= KEYCTL_SUPPORTS_DECRYPT; + } - len = crypto_akcipher_maxsize(tfm); info->key_size = len * 8; if (strncmp(pkey->pkey_algo, "ecdsa", 5) == 0) { @@ -208,17 +250,16 @@ static int software_key_query(const struct kernel_pkey_params *params, info->max_enc_size = len; info->max_dec_size = len; - info->supported_ops = (KEYCTL_SUPPORTS_ENCRYPT | - KEYCTL_SUPPORTS_VERIFY); - if (pkey->key_is_private) - info->supported_ops |= (KEYCTL_SUPPORTS_DECRYPT | - KEYCTL_SUPPORTS_SIGN); + ret = 0; +error_free_tfm: + if (isdsa) + crypto_free_dsa(dsa); + else + crypto_free_akcipher(tfm); error_free_key: kfree(key); -error_free_tfm: - crypto_free_akcipher(tfm); pr_devel("<==%s() = %d\n", __func__, ret); return ret; } @@ -230,34 +271,26 @@ static int software_key_eds_op(struct kernel_pkey_params *params, const void *in, void *out) { const struct public_key *pkey = params->key->payload.data[asym_crypto]; - struct akcipher_request *req; - struct crypto_akcipher *tfm; - struct crypto_wait cwait; - struct scatterlist in_sg, out_sg; char alg_name[CRYPTO_MAX_ALG_NAME]; + struct crypto_akcipher *tfm; + struct crypto_dsa *dsa; char *key, *ptr; + bool isdsa; + int ksz; int ret; pr_devel("==>%s()\n", __func__); ret = software_key_determine_akcipher(pkey, params->encoding, - params->hash_algo, alg_name); + params->hash_algo, alg_name, + &isdsa, params->op); if (ret < 0) return ret; - tfm = crypto_alloc_akcipher(alg_name, 0, 0); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); - - ret = -ENOMEM; - req = akcipher_request_alloc(tfm, GFP_KERNEL); - if (!req) - goto error_free_tfm; - key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen, GFP_KERNEL); if (!key) - goto error_free_req; + return -ENOMEM; memcpy(key, pkey->key, pkey->keylen); ptr = key + pkey->keylen; @@ -265,47 +298,70 @@ static int software_key_eds_op(struct kernel_pkey_params *params, ptr = pkey_pack_u32(ptr, pkey->paramlen); memcpy(ptr, pkey->params, pkey->paramlen); - if (pkey->key_is_private) - ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen); - else - ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen); - if (ret) - goto error_free_key; + if (isdsa) { + dsa = crypto_alloc_dsa(alg_name, 0, 0); + if (IS_ERR(dsa)) + goto error_free_key; - sg_init_one(&in_sg, in, params->in_len); - sg_init_one(&out_sg, out, params->out_len); - akcipher_request_set_crypt(req, &in_sg, &out_sg, params->in_len, - params->out_len); - crypto_init_wait(&cwait); - akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP, - crypto_req_done, &cwait); + if (pkey->key_is_private) + ret = crypto_dsa_set_privkey(dsa, key, pkey->keylen); + else + ret = crypto_dsa_set_pubkey(dsa, key, pkey->keylen); + if (ret) + goto error_free_tfm; + + ksz = crypto_dsa_maxsize(dsa); + } else { + tfm = crypto_alloc_akcipher(alg_name, 0, 0); + if (IS_ERR(tfm)) + goto error_free_key; + + if (pkey->key_is_private) + ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen); + else + ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen); + if (ret) + goto error_free_tfm; + + ksz = crypto_akcipher_maxsize(tfm); + } + + ret = -EINVAL; /* Perform the encryption calculation. */ switch (params->op) { case kernel_pkey_encrypt: - ret = crypto_akcipher_encrypt(req); + if (isdsa) + break; + ret = crypto_akcipher_sync_encrypt(tfm, in, params->in_len, + out, params->out_len); break; case kernel_pkey_decrypt: - ret = crypto_akcipher_decrypt(req); + if (isdsa) + break; + ret = crypto_akcipher_sync_decrypt(tfm, in, params->in_len, + out, params->out_len); break; case kernel_pkey_sign: - ret = crypto_akcipher_sign(req); + if (!isdsa) + break; + ret = crypto_dsa_sign(dsa, in, params->in_len, + out, params->out_len); break; default: BUG(); } - ret = crypto_wait_req(ret, &cwait); if (ret == 0) - ret = req->dst_len; + ret = ksz; +error_free_tfm: + if (isdsa) + crypto_free_dsa(dsa); + else + crypto_free_akcipher(tfm); error_free_key: kfree(key); -error_free_req: - akcipher_request_free(req); -error_free_tfm: - crypto_free_akcipher(tfm); pr_devel("<==%s() = %d\n", __func__, ret); return ret; } @@ -316,12 +372,10 @@ static int software_key_eds_op(struct kernel_pkey_params *params, int public_key_verify_signature(const struct public_key *pkey, const struct public_key_signature *sig) { - struct crypto_wait cwait; - struct crypto_akcipher *tfm; - struct akcipher_request *req; - struct scatterlist src_sg[2]; char alg_name[CRYPTO_MAX_ALG_NAME]; + struct crypto_dsa *dsa; char *key, *ptr; + bool isdsa; int ret; pr_devel("==>%s()\n", __func__); @@ -346,23 +400,19 @@ int public_key_verify_signature(const struct public_key *pkey, } ret = software_key_determine_akcipher(pkey, sig->encoding, - sig->hash_algo, alg_name); + sig->hash_algo, alg_name, + &isdsa, kernel_pkey_verify); if (ret < 0) return ret; - tfm = crypto_alloc_akcipher(alg_name, 0, 0); - if (IS_ERR(tfm)) - return PTR_ERR(tfm); - - ret = -ENOMEM; - req = akcipher_request_alloc(tfm, GFP_KERNEL); - if (!req) - goto error_free_tfm; + dsa = crypto_alloc_dsa(alg_name, 0, 0); + if (IS_ERR(dsa)) + return PTR_ERR(dsa); key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen, GFP_KERNEL); if (!key) - goto error_free_req; + goto error_free_tfm; memcpy(key, pkey->key, pkey->keylen); ptr = key + pkey->keylen; @@ -371,29 +421,19 @@ int public_key_verify_signature(const struct public_key *pkey, memcpy(ptr, pkey->params, pkey->paramlen); if (pkey->key_is_private) - ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen); + ret = crypto_dsa_set_privkey(dsa, key, pkey->keylen); else - ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen); + ret = crypto_dsa_set_pubkey(dsa, key, pkey->keylen); 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); - akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size, - sig->digest_size); - crypto_init_wait(&cwait); - akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP, - crypto_req_done, &cwait); - ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait); + ret = crypto_dsa_verify(dsa, sig->s, sig->s_size, + sig->digest, sig->digest_size); error_free_key: kfree(key); -error_free_req: - akcipher_request_free(req); error_free_tfm: - crypto_free_akcipher(tfm); + crypto_free_dsa(dsa); pr_devel("<==%s() = %d\n", __func__, ret); if (WARN_ON_ONCE(ret > 0)) ret = -EINVAL;