@@ -167,10 +167,7 @@ int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data)
unsigned int len;
u8 *buf;
- if (data->dst)
- mlen = max(data->slen, data->dlen);
- else
- mlen = data->slen + data->dlen;
+ mlen = max(data->slen, data->dlen);
len = sizeof(*req) + reqsize + mlen;
if (len < mlen)
@@ -189,8 +186,7 @@ int crypto_akcipher_sync_prep(struct crypto_akcipher_sync_data *data)
sg = &data->sg;
sg_init_one(sg, buf, mlen);
- akcipher_request_set_crypt(req, sg, data->dst ? sg : NULL,
- data->slen, data->dlen);
+ 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,
@@ -203,8 +199,7 @@ EXPORT_SYMBOL_GPL(crypto_akcipher_sync_prep);
int crypto_akcipher_sync_post(struct crypto_akcipher_sync_data *data, int err)
{
err = crypto_wait_req(err, &data->cwait);
- if (data->dst)
- memcpy(data->dst, data->buf, data->dlen);
+ memcpy(data->dst, data->buf, data->dlen);
data->dlen = data->req->dst_len;
kfree_sensitive(data->req);
return err;
@@ -9,7 +9,6 @@
#include <crypto/akcipher.h>
#include <crypto/ecdh.h>
#include <linux/asn1_decoder.h>
-#include <linux/scatterlist.h>
#include "ecdsasignature.asn1.h"
@@ -135,37 +134,23 @@ static int ecdsa_verify(struct akcipher_request *req)
.curve = ctx->curve,
};
u64 hash[ECC_MAX_DIGITS];
- unsigned char *buffer;
int ret;
if (unlikely(!ctx->pub_key_set))
return -EINVAL;
- buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- sg_pcopy_to_buffer(req->src,
- sg_nents_for_len(req->src, req->src_len + req->dst_len),
- buffer, req->src_len + req->dst_len, 0);
-
ret = asn1_ber_decoder(&ecdsasignature_decoder, &sig_ctx,
- buffer, req->src_len);
+ req->sig, req->sig_len);
if (ret < 0)
- goto error;
+ return ret;
- if (bufsize > req->dst_len)
- bufsize = req->dst_len;
+ if (bufsize > req->digest_len)
+ bufsize = req->digest_len;
- ecc_digits_from_bytes(buffer + req->src_len, bufsize,
+ ecc_digits_from_bytes(req->digest, bufsize,
hash, ctx->curve->g.ndigits);
- ret = _ecdsa_verify(ctx, hash, sig_ctx.r, sig_ctx.s);
-
-error:
- kfree(buffer);
-
- return ret;
+ return _ecdsa_verify(ctx, hash, sig_ctx.r, sig_ctx.s);
}
static int ecdsa_ecc_ctx_init(struct ecc_ctx *ctx, unsigned int curve_id)
@@ -23,7 +23,6 @@
#include <crypto/internal/ecc.h>
#include <crypto/akcipher.h>
#include <linux/oid_registry.h>
-#include <linux/scatterlist.h>
#include "ecrdsa_params.asn1.h"
#include "ecrdsa_pub_key.asn1.h"
#include "ecrdsa_defs.h"
@@ -72,8 +71,6 @@ static int ecrdsa_verify(struct akcipher_request *req)
{
struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
struct ecrdsa_ctx *ctx = akcipher_tfm_ctx(tfm);
- unsigned char sig[ECRDSA_MAX_SIG_SIZE];
- unsigned char digest[STREEBOG512_DIGEST_SIZE];
unsigned int ndigits = req->dst_len / sizeof(u64);
u64 r[ECRDSA_MAX_DIGITS]; /* witness (r) */
u64 _r[ECRDSA_MAX_DIGITS]; /* -r */
@@ -91,25 +88,18 @@ static int ecrdsa_verify(struct akcipher_request *req)
*/
if (!ctx->curve ||
!ctx->digest ||
- !req->src ||
+ !req->sig ||
!ctx->pub_key.x ||
- req->dst_len != ctx->digest_len ||
- req->dst_len != ctx->curve->g.ndigits * sizeof(u64) ||
+ req->digest_len != ctx->digest_len ||
+ req->digest_len != ctx->curve->g.ndigits * sizeof(u64) ||
ctx->pub_key.ndigits != ctx->curve->g.ndigits ||
- req->dst_len * 2 != req->src_len ||
- WARN_ON(req->src_len > sizeof(sig)) ||
- WARN_ON(req->dst_len > sizeof(digest)))
+ req->digest_len * 2 != req->sig_len ||
+ WARN_ON(req->sig_len > ECRDSA_MAX_SIG_SIZE) ||
+ WARN_ON(req->digest_len > STREEBOG512_DIGEST_SIZE))
return -EBADMSG;
- sg_copy_to_buffer(req->src, sg_nents_for_len(req->src, req->src_len),
- sig, req->src_len);
- sg_pcopy_to_buffer(req->src,
- sg_nents_for_len(req->src,
- req->src_len + req->dst_len),
- digest, req->dst_len, req->src_len);
-
- vli_from_be64(s, sig, ndigits);
- vli_from_be64(r, sig + ndigits * sizeof(u64), ndigits);
+ vli_from_be64(s, req->sig, ndigits);
+ vli_from_be64(r, req->sig + ndigits * sizeof(u64), ndigits);
/* Step 1: verify that 0 < r < q, 0 < s < q */
if (vli_is_zero(r, ndigits) ||
@@ -120,7 +110,7 @@ static int ecrdsa_verify(struct akcipher_request *req)
/* Step 2: calculate hash (h) of the message (passed as input) */
/* Step 3: calculate e = h \mod q */
- vli_from_le64(e, digest, ndigits);
+ vli_from_le64(e, req->digest, ndigits);
if (vli_cmp(e, ctx->curve->n, ndigits) >= 0)
vli_sub(e, e, ctx->curve->n, ndigits);
if (vli_is_zero(e, ndigits))
@@ -182,8 +182,8 @@ static unsigned int pkcs1pad_get_max_size(struct crypto_akcipher *tfm)
return ctx->key_size;
}
-static void pkcs1pad_sg_set_buf(struct scatterlist *sg, void *buf, size_t len,
- struct scatterlist *next)
+static void pkcs1pad_sg_set_buf(struct scatterlist *sg, const void *buf,
+ size_t len, struct scatterlist *next)
{
int nsegs = next ? 2 : 1;
@@ -459,8 +459,7 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err)
struct akcipher_instance *inst = akcipher_alg_instance(tfm);
struct pkcs1pad_inst_ctx *ictx = akcipher_instance_ctx(inst);
const struct rsa_asn1_template *digest_info = ictx->digest_info;
- const unsigned int sig_size = req->src_len;
- const unsigned int digest_size = req->dst_len;
+ const unsigned int digest_size = req->digest_len;
unsigned int dst_len;
unsigned int pos;
u8 *out_buf;
@@ -512,14 +511,8 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err)
req->dst_len = dst_len - pos;
goto done;
}
- /* Extract appended digest. */
- sg_pcopy_to_buffer(req->src,
- sg_nents_for_len(req->src, sig_size + digest_size),
- req_ctx->out_buf + ctx->key_size,
- digest_size, sig_size);
/* Do the actual verification step. */
- if (memcmp(req_ctx->out_buf + ctx->key_size, out_buf + pos,
- digest_size) != 0)
+ if (memcmp(req->digest, out_buf + pos, digest_size) != 0)
err = -EKEYREJECTED;
done:
kfree_sensitive(req_ctx->out_buf);
@@ -553,27 +546,29 @@ static int pkcs1pad_verify(struct akcipher_request *req)
struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
struct pkcs1pad_ctx *ctx = akcipher_tfm_ctx(tfm);
struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req);
- const unsigned int sig_size = req->src_len;
- const unsigned int digest_size = req->dst_len;
+ const unsigned int sig_size = req->sig_len;
+ const unsigned int digest_size = req->digest_len;
int err;
- if (WARN_ON(req->dst) || WARN_ON(!digest_size) ||
+ if (WARN_ON(!digest_size) ||
!ctx->key_size || sig_size != ctx->key_size)
return -EINVAL;
- req_ctx->out_buf = kmalloc(ctx->key_size + digest_size, GFP_KERNEL);
+ req_ctx->out_buf = kmalloc(ctx->key_size, GFP_KERNEL);
if (!req_ctx->out_buf)
return -ENOMEM;
pkcs1pad_sg_set_buf(req_ctx->out_sg, req_ctx->out_buf,
ctx->key_size, NULL);
+ pkcs1pad_sg_set_buf(req_ctx->in_sg, req->sig,
+ req->sig_len, NULL);
akcipher_request_set_tfm(&req_ctx->child_req, ctx->child);
akcipher_request_set_callback(&req_ctx->child_req, req->base.flags,
pkcs1pad_verify_complete_cb, req);
/* Reuse input buffer, output to a new buffer */
- akcipher_request_set_crypt(&req_ctx->child_req, req->src,
+ akcipher_request_set_crypt(&req_ctx->child_req, req_ctx->in_sg,
req_ctx->out_sg, sig_size, ctx->key_size);
err = crypto_akcipher_encrypt(&req_ctx->child_req);
@@ -98,22 +98,22 @@ int crypto_sig_verify(struct crypto_sig *tfm,
const void *digest, unsigned int dlen)
{
struct crypto_akcipher **ctx = crypto_sig_ctx(tfm);
- struct crypto_akcipher_sync_data data = {
- .tfm = *ctx,
- .src = src,
- .slen = slen,
- .dlen = dlen,
- };
+ struct crypto_akcipher *child_tfm = *ctx;
+ struct akcipher_request *req;
int err;
- err = crypto_akcipher_sync_prep(&data);
- if (err)
- return err;
+ req = kzalloc(sizeof(*req) + crypto_akcipher_reqsize(child_tfm),
+ GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ akcipher_request_set_tfm(req, child_tfm);
+ akcipher_request_set_crypt(req, src, digest, slen, dlen);
- memcpy(data.buf + slen, digest, dlen);
+ err = crypto_akcipher_verify(req);
- return crypto_akcipher_sync_post(&data,
- crypto_akcipher_verify(data.req));
+ kfree_sensitive(req);
+ return err;
}
EXPORT_SYMBOL_GPL(crypto_sig_verify);
@@ -4105,7 +4105,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
struct crypto_wait wait;
unsigned int out_len_max, out_len = 0;
int err = -ENOMEM;
- struct scatterlist src, dst, src_tab[3];
+ struct scatterlist src, dst, src_tab[2];
const char *m, *c;
unsigned int m_size, c_size;
const char *op;
@@ -4169,16 +4169,16 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
goto free_all;
memcpy(xbuf[0], m, m_size);
- sg_init_table(src_tab, 3);
- sg_set_buf(&src_tab[0], xbuf[0], 8);
- sg_set_buf(&src_tab[1], xbuf[0] + 8, m_size - 8);
if (vecs->siggen_sigver_test) {
if (WARN_ON(c_size > PAGE_SIZE))
goto free_all;
memcpy(xbuf[1], c, c_size);
- sg_set_buf(&src_tab[2], xbuf[1], c_size);
- akcipher_request_set_crypt(req, src_tab, NULL, m_size, c_size);
+ akcipher_request_set_crypt(req, xbuf[0], xbuf[1],
+ m_size, c_size);
} else {
+ sg_init_table(src_tab, 2);
+ sg_set_buf(&src_tab[0], xbuf[0], 8);
+ sg_set_buf(&src_tab[1], xbuf[0] + 8, m_size - 8);
sg_init_one(&dst, outbuf_enc, out_len_max);
akcipher_request_set_crypt(req, src_tab, &dst, m_size,
out_len_max);
@@ -16,28 +16,39 @@
*
* @base: Common attributes for async crypto requests
* @src: Source data
- * For verify op this is signature + digest, in that case
- * total size of @src is @src_len + @dst_len.
- * @dst: Destination data (Should be NULL for verify op)
+ * @dst: Destination data
* @src_len: Size of the input buffer
- * For verify op it's size of signature part of @src, this part
- * is supposed to be operated by cipher.
- * @dst_len: Size of @dst buffer (for all ops except verify).
+ * @dst_len: Size of @dst buffer
* It needs to be at least as big as the expected result
* depending on the operation.
* After operation it will be updated with the actual size of the
* result.
* In case of error where the dst sgl size was insufficient,
* it will be updated to the size required for the operation.
- * For verify op this is size of digest part in @src.
+ * @sig: Signature
+ * @digest: Digest
+ * @sig_len: Size of @sig
+ * @digest_len: Size of @digest
* @__ctx: Start of private context data
*/
struct akcipher_request {
struct crypto_async_request base;
- struct scatterlist *src;
- struct scatterlist *dst;
- unsigned int src_len;
- unsigned int dst_len;
+ union {
+ struct {
+ /* sign, encrypt, decrypt operations */
+ struct scatterlist *src;
+ struct scatterlist *dst;
+ unsigned int src_len;
+ unsigned int dst_len;
+ };
+ struct {
+ /* verify operation */
+ const void *sig;
+ const void *digest;
+ unsigned int sig_len;
+ unsigned int digest_len;
+ };
+ };
void *__ctx[] CRYPTO_MINALIGN_ATTR;
};
@@ -242,20 +253,18 @@ static inline void akcipher_request_set_callback(struct akcipher_request *req,
* Sets parameters required by crypto operation
*
* @req: public key request
- * @src: ptr to input scatter list
- * @dst: ptr to output scatter list or NULL for verify op
- * @src_len: size of the src input scatter list to be processed
- * @dst_len: size of the dst output scatter list or size of signature
- * portion in @src for verify op
+ * @src: ptr to input scatter list or signature for verify op
+ * @dst: ptr to output scatter list or digest for verify op
+ * @src_len: size of @src
+ * @dst_len: size of @dst
*/
static inline void akcipher_request_set_crypt(struct akcipher_request *req,
- struct scatterlist *src,
- struct scatterlist *dst,
+ const void *src, const void *dst,
unsigned int src_len,
unsigned int dst_len)
{
- req->src = src;
- req->dst = dst;
+ req->sig = src;
+ req->digest = dst;
req->src_len = src_len;
req->dst_len = dst_len;
}
@@ -372,10 +381,6 @@ static inline int crypto_akcipher_sign(struct akcipher_request *req)
*
* @req: asymmetric key request
*
- * Note: req->dst should be NULL, req->src should point to SG of size
- * (req->src_size + req->dst_size), containing signature (of req->src_size
- * length) with appended digest (of req->dst_size length).
- *
* Return: zero on verification success; error code in case of error.
*/
static inline int crypto_akcipher_verify(struct akcipher_request *req)
Commit 6cb8815f41a9 ("crypto: sig - Add interface for sign/verify") introduced an API which accepts kernel buffers instead of sglists for signature generation and verification. Commit 63ba4d67594a ("KEYS: asymmetric: Use new crypto interface without scatterlists") converted the sole user in the tree to the new API. Although the API externally accepts kernel buffers, internally it still converts them to sglists, which results in overhead for asymmetric algorithms because they need to copy the sglists back into kernel buffers. Take the next step and switch signature verification over to using kernel buffers internally, thereby avoiding the sglists overhead. Because all ->verify implementations are synchronous, forego invocation of crypto_akcipher_sync_{prep,post}() and call crypto_akcipher_verify() directly from crypto_sig_verify(). Signed-off-by: Lukas Wunner <lukas@wunner.de> --- crypto/akcipher.c | 11 +++----- crypto/ecdsa.c | 27 +++++--------------- crypto/ecrdsa.c | 28 +++++++-------------- crypto/rsa-pkcs1pad.c | 27 ++++++++------------ crypto/sig.c | 24 +++++++++--------- crypto/testmgr.c | 12 ++++----- include/crypto/akcipher.h | 53 +++++++++++++++++++++------------------ 7 files changed, 76 insertions(+), 106 deletions(-)