From patchwork Tue Jun 13 09:38:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herbert Xu X-Patchwork-Id: 13278193 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 49544C88CB6 for ; Tue, 13 Jun 2023 09:38:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238412AbjFMJie (ORCPT ); Tue, 13 Jun 2023 05:38:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55848 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239111AbjFMJib (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 CE99C195; Tue, 13 Jun 2023 02:38:28 -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 1q90TZ-002LQB-2l; Tue, 13 Jun 2023 17:38:10 +0800 Received: by loth.rohan.me.apana.org.au (sSMTP sendmail emulation); Tue, 13 Jun 2023 17:38:09 +0800 From: "Herbert Xu" Date: Tue, 13 Jun 2023 17:38:09 +0800 Subject: [PATCH 1/5] crypto: akcipher - Add sync interface without SG lists 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: keyrings@vger.kernel.org The only user of akcipher does not use SG lists. Therefore forcing users to use SG lists only results unnecessary overhead. Add a new interface that supports arbitrary kernel pointers. For the time being the copy will be performed unconditionally. But this will go away once the underlying interface is updated. Note also that only encryption and decryption is addressed by this patch as sign/verify will go into a new interface (dsa). Signed-off-by: Herbert Xu --- crypto/akcipher.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++ include/crypto/akcipher.h | 36 +++++++++++++++++ 2 files changed, 131 insertions(+) diff --git a/crypto/akcipher.c b/crypto/akcipher.c index 7960ceb528c3..2d10b58c4010 100644 --- a/crypto/akcipher.c +++ b/crypto/akcipher.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,19 @@ #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; +}; + static int __maybe_unused crypto_akcipher_report( struct sk_buff *skb, struct crypto_alg *alg) { @@ -186,5 +200,86 @@ 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) +{ + unsigned int reqsize = crypto_akcipher_reqsize(data->tfm); + unsigned int mlen = max(data->slen, data->dlen); + struct akcipher_request *req; + struct scatterlist *sg; + unsigned int len; + u8 *buf; + + len = sizeof(*req) + reqsize + mlen; + if (len < mlen) + return -EOVERFLOW; + + req = kzalloc(len, GFP_KERNEL); + if (!req) + return -ENOMEM; + + data->req = req; + + buf = (u8 *)(req + 1) + reqsize; + data->buf = buf; + memcpy(buf, data->src, data->slen); + + sg = &data->sg; + sg_init_one(sg, buf, mlen); + akcipher_request_set_crypt(req, sg, sg, data->slen, data->dlen); + + crypto_init_wait(&data->cwait); + akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, + crypto_req_done, &data->cwait); + + return 0; +} + +static 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); + data->dlen = data->req->dst_len; + kfree_sensitive(data->req); + return err; +} + +int crypto_akcipher_sync_encrypt(struct crypto_akcipher *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + struct crypto_akcipher_sync_data data = { + .tfm = tfm, + .src = src, + .dst = dst, + .slen = slen, + .dlen = dlen, + }; + + return crypto_akcipher_sync_prep(&data) ?: + crypto_akcipher_sync_post(&data, + crypto_akcipher_encrypt(data.req)); +} +EXPORT_SYMBOL_GPL(crypto_akcipher_sync_encrypt); + +int crypto_akcipher_sync_decrypt(struct crypto_akcipher *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen) +{ + struct crypto_akcipher_sync_data data = { + .tfm = tfm, + .src = src, + .dst = dst, + .slen = slen, + .dlen = dlen, + }; + + return crypto_akcipher_sync_prep(&data) ?: + crypto_akcipher_sync_post(&data, + crypto_akcipher_decrypt(data.req)) ?: + data.dlen; +} +EXPORT_SYMBOL_GPL(crypto_akcipher_sync_decrypt); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic public key cipher type"); diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h index f35fd653e4e5..670508f1dca1 100644 --- a/include/crypto/akcipher.h +++ b/include/crypto/akcipher.h @@ -373,6 +373,42 @@ static inline int crypto_akcipher_decrypt(struct akcipher_request *req) return crypto_akcipher_errstat(alg, alg->decrypt(req)); } +/** + * crypto_akcipher_sync_encrypt() - Invoke public key encrypt operation + * + * Function invokes the specific public key encrypt operation for a given + * public key algorithm + * + * @tfm: AKCIPHER tfm handle allocated with crypto_alloc_akcipher() + * @src: source buffer + * @slen: source length + * @dst: destinatino obuffer + * @dlen: destination length + * + * Return: zero on success; error code in case of error + */ +int crypto_akcipher_sync_encrypt(struct crypto_akcipher *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen); + +/** + * crypto_akcipher_sync_decrypt() - Invoke public key decrypt operation + * + * Function invokes the specific public key decrypt operation for a given + * public key algorithm + * + * @tfm: AKCIPHER tfm handle allocated with crypto_alloc_akcipher() + * @src: source buffer + * @slen: source length + * @dst: destinatino obuffer + * @dlen: destination length + * + * Return: Output length on success; error code in case of error + */ +int crypto_akcipher_sync_decrypt(struct crypto_akcipher *tfm, + const void *src, unsigned int slen, + void *dst, unsigned int dlen); + /** * crypto_akcipher_sign() - Invoke public key sign operation * 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: 13278194 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 224DDC7EE2E for ; Tue, 13 Jun 2023 09:38:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239111AbjFMJif (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: keyrings@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: 13278192 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 DD06EC7EE2E for ; Tue, 13 Jun 2023 09:38:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238745AbjFMJid (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: keyrings@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:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herbert Xu X-Patchwork-Id: 13278195 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 A05E7C7EE29 for ; Tue, 13 Jun 2023 09:38:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239647AbjFMJij (ORCPT ); Tue, 13 Jun 2023 05:38:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55960 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239967AbjFMJig (ORCPT ); Tue, 13 Jun 2023 05:38:36 -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 0BF1DE3; 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 1q90Tf-002LR5-F7; Tue, 13 Jun 2023 17:38:16 +0800 Received: by loth.rohan.me.apana.org.au (sSMTP sendmail emulation); Tue, 13 Jun 2023 17:38:15 +0800 From: "Herbert Xu" Date: Tue, 13 Jun 2023 17:38:15 +0800 Subject: [PATCH 4/5] KEYS: asymmetric: Move sm2 code into x509_public_key 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: keyrings@vger.kernel.org The sm2 certificate requires a modified digest. Move the code for the hashing from the signature verification path into the code where we generate the digest. Signed-off-by: Herbert Xu --- crypto/asymmetric_keys/public_key.c | 67 ------------------- crypto/asymmetric_keys/x509_public_key.c | 28 +++++--- crypto/sm2.c | 106 ++++++++++++++++++++----------- include/crypto/public_key.h | 2 include/crypto/sm2.h | 12 --- 5 files changed, 93 insertions(+), 122 deletions(-) diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index eca5671ad3f2..c795a12a3599 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -18,8 +18,6 @@ #include #include #include -#include -#include MODULE_DESCRIPTION("In-software asymmetric public-key subtype"); MODULE_AUTHOR("Red Hat, Inc."); @@ -312,65 +310,6 @@ static int software_key_eds_op(struct kernel_pkey_params *params, 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); - - /* SM2 signatures always use the SM3 hash algorithm */ - if (!sig->hash_algo || strcmp(sig->hash_algo, "sm3") != 0) - return -EINVAL; - - 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. */ @@ -438,12 +377,6 @@ int public_key_verify_signature(const struct public_key *pkey, if (ret) goto error_free_key; - if (strcmp(pkey->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_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 0b4943a4592b..2fca030a6290 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -6,13 +6,15 @@ */ #define pr_fmt(fmt) "X.509: "fmt +#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include +#include #include "asymmetric_keys.h" #include "x509_parser.h" @@ -30,9 +32,6 @@ int x509_get_sig_params(struct x509_certificate *cert) pr_devel("==>%s()\n", __func__); - sig->data = cert->tbs; - sig->data_size = cert->tbs_size; - sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL); if (!sig->s) return -ENOMEM; @@ -65,7 +64,20 @@ int x509_get_sig_params(struct x509_certificate *cert) desc->tfm = tfm; - ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size, sig->digest); + if (strcmp(cert->pub->pkey_algo, "sm2") == 0) { + ret = strcmp(sig->hash_algo, "sm3") != 0 ? -EINVAL : + crypto_shash_init(desc) ?: + sm2_compute_z_digest(desc, cert->pub->key, + cert->pub->keylen, sig->digest) ?: + crypto_shash_init(desc) ?: + crypto_shash_update(desc, sig->digest, + sig->digest_size) ?: + crypto_shash_finup(desc, cert->tbs, cert->tbs_size, + sig->digest); + } else + ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size, + sig->digest); + if (ret < 0) goto error_2; diff --git a/crypto/sm2.c b/crypto/sm2.c index ed9307dac3d1..285b3cb7c0bc 100644 --- a/crypto/sm2.c +++ b/crypto/sm2.c @@ -13,11 +13,14 @@ #include #include #include -#include #include #include #include "sm2signature.asn1.h" +/* The default user id as specified in GM/T 0009-2012 */ +#define SM2_DEFAULT_USERID "1234567812345678" +#define SM2_DEFAULT_USERID_LEN 16 + #define MPI_NBYTES(m) ((mpi_get_nbits(m) + 7) / 8) struct ecc_domain_parms { @@ -60,6 +63,9 @@ static const struct ecc_domain_parms sm2_ecp = { .h = 1 }; +static int __sm2_set_pub_key(struct mpi_ec_ctx *ec, + const void *key, unsigned int keylen); + static int sm2_ec_ctx_init(struct mpi_ec_ctx *ec) { const struct ecc_domain_parms *ecp = &sm2_ecp; @@ -213,12 +219,13 @@ int sm2_get_signature_s(void *context, size_t hdrlen, unsigned char tag, return 0; } -static int sm2_z_digest_update(struct sm3_state *sctx, - MPI m, unsigned int pbytes) +static int sm2_z_digest_update(struct shash_desc *desc, + MPI m, unsigned int pbytes) { static const unsigned char zero[32]; unsigned char *in; unsigned int inlen; + int err; in = mpi_get_buffer(m, &inlen, NULL); if (!in) @@ -226,21 +233,22 @@ static int sm2_z_digest_update(struct sm3_state *sctx, if (inlen < pbytes) { /* padding with zero */ - sm3_update(sctx, zero, pbytes - inlen); - sm3_update(sctx, in, inlen); + err = crypto_shash_update(desc, zero, pbytes - inlen) ?: + crypto_shash_update(desc, in, inlen); } else if (inlen > pbytes) { /* skip the starting zero */ - sm3_update(sctx, in + inlen - pbytes, pbytes); + err = crypto_shash_update(desc, in + inlen - pbytes, pbytes); } else { - sm3_update(sctx, in, inlen); + err = crypto_shash_update(desc, in, inlen); } kfree(in); - return 0; + return err; } -static int sm2_z_digest_update_point(struct sm3_state *sctx, - MPI_POINT point, struct mpi_ec_ctx *ec, unsigned int pbytes) +static int sm2_z_digest_update_point(struct shash_desc *desc, + MPI_POINT point, struct mpi_ec_ctx *ec, + unsigned int pbytes) { MPI x, y; int ret = -EINVAL; @@ -248,50 +256,68 @@ static int sm2_z_digest_update_point(struct sm3_state *sctx, x = mpi_new(0); y = mpi_new(0); - if (!mpi_ec_get_affine(x, y, point, ec) && - !sm2_z_digest_update(sctx, x, pbytes) && - !sm2_z_digest_update(sctx, y, pbytes)) - ret = 0; + ret = mpi_ec_get_affine(x, y, point, ec) ? -EINVAL : + sm2_z_digest_update(desc, x, pbytes) ?: + sm2_z_digest_update(desc, y, pbytes); mpi_free(x); mpi_free(y); return ret; } -int sm2_compute_z_digest(struct crypto_akcipher *tfm, - const unsigned char *id, size_t id_len, - unsigned char dgst[SM3_DIGEST_SIZE]) +int sm2_compute_z_digest(struct shash_desc *desc, + const void *key, unsigned int keylen, void *dgst) { - struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm); - uint16_t bits_len; - unsigned char entl[2]; - struct sm3_state sctx; + struct mpi_ec_ctx *ec; + unsigned int bits_len; unsigned int pbytes; + u8 entl[2]; + int err; - if (id_len > (USHRT_MAX / 8) || !ec->Q) - return -EINVAL; + ec = kmalloc(sizeof(*ec), GFP_KERNEL); + if (!ec) + return -ENOMEM; + + err = __sm2_set_pub_key(ec, key, keylen); + if (err) + goto out_free_ec; - bits_len = (uint16_t)(id_len * 8); + bits_len = SM2_DEFAULT_USERID_LEN * 8; entl[0] = bits_len >> 8; entl[1] = bits_len & 0xff; pbytes = MPI_NBYTES(ec->p); /* ZA = H256(ENTLA | IDA | a | b | xG | yG | xA | yA) */ - sm3_init(&sctx); - sm3_update(&sctx, entl, 2); - sm3_update(&sctx, id, id_len); - - if (sm2_z_digest_update(&sctx, ec->a, pbytes) || - sm2_z_digest_update(&sctx, ec->b, pbytes) || - sm2_z_digest_update_point(&sctx, ec->G, ec, pbytes) || - sm2_z_digest_update_point(&sctx, ec->Q, ec, pbytes)) - return -EINVAL; + err = crypto_shash_init(desc); + if (err) + goto out_deinit_ec; - sm3_final(&sctx, dgst); - return 0; + err = crypto_shash_update(desc, entl, 2); + if (err) + goto out_deinit_ec; + + err = crypto_shash_update(desc, SM2_DEFAULT_USERID, + SM2_DEFAULT_USERID_LEN); + if (err) + goto out_deinit_ec; + + err = sm2_z_digest_update(desc, ec->a, pbytes) ?: + sm2_z_digest_update(desc, ec->b, pbytes) ?: + sm2_z_digest_update_point(desc, ec->G, ec, pbytes) ?: + sm2_z_digest_update_point(desc, ec->Q, ec, pbytes); + if (err) + goto out_deinit_ec; + + err = crypto_shash_final(desc, dgst); + +out_deinit_ec: + sm2_ec_ctx_deinit(ec); +out_free_ec: + kfree(ec); + return err; } -EXPORT_SYMBOL(sm2_compute_z_digest); +EXPORT_SYMBOL_GPL(sm2_compute_z_digest); static int _sm2_verify(struct mpi_ec_ctx *ec, MPI hash, MPI sig_r, MPI sig_s) { @@ -391,6 +417,14 @@ static int sm2_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) { struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm); + + return __sm2_set_pub_key(ec, key, keylen); + +} + +static int __sm2_set_pub_key(struct mpi_ec_ctx *ec, + const void *key, unsigned int keylen) +{ MPI a; int rc; diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index 653992a6e941..8fadd561c50e 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h @@ -48,8 +48,6 @@ struct public_key_signature { const char *pkey_algo; const char *hash_algo; const char *encoding; - const void *data; - unsigned int data_size; }; extern void public_key_signature_free(struct public_key_signature *sig); diff --git a/include/crypto/sm2.h b/include/crypto/sm2.h index af452556dcd4..7094d75ed54c 100644 --- a/include/crypto/sm2.h +++ b/include/crypto/sm2.h @@ -11,15 +11,9 @@ #ifndef _CRYPTO_SM2_H #define _CRYPTO_SM2_H -#include -#include +struct shash_desc; -/* The default user id as specified in GM/T 0009-2012 */ -#define SM2_DEFAULT_USERID "1234567812345678" -#define SM2_DEFAULT_USERID_LEN 16 - -extern int sm2_compute_z_digest(struct crypto_akcipher *tfm, - const unsigned char *id, size_t id_len, - unsigned char dgst[SM3_DIGEST_SIZE]); +int sm2_compute_z_digest(struct shash_desc *desc, + const void *key, unsigned int keylen, void *dgst); #endif /* _CRYPTO_SM2_H */ 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: 13278196 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 E1809C7EE29 for ; Tue, 13 Jun 2023 09:38:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240740AbjFMJim (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: keyrings@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;