crypto: ecdh - fix to allow multi segment scatterlists
authorJames Bottomley <James.Bottomley@HansenPartnership.com>
Thu, 1 Mar 2018 22:37:42 +0000 (14:37 -0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Fri, 9 Mar 2018 14:45:49 +0000 (22:45 +0800)
Apparently the ecdh use case was in bluetooth which always has single
element scatterlists, so the ecdh module was hard coded to expect
them.  Now we're using this in TPM, we need multi-element
scatterlists, so remove this limitation.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
crypto/ecdh.c

index 3aca0933ec443ec5c56e852c9c03a13130e05c5a..d2ec33f0e098fce60934811f5f7195d979488a08 100644 (file)
@@ -89,12 +89,19 @@ static int ecdh_compute_value(struct kpp_request *req)
                if (!shared_secret)
                        goto free_pubkey;
 
-               copied = sg_copy_to_buffer(req->src, 1, public_key,
-                                          public_key_sz);
-               if (copied != public_key_sz) {
-                       ret = -EINVAL;
+               /* from here on it's invalid parameters */
+               ret = -EINVAL;
+
+               /* must have exactly two points to be on the curve */
+               if (public_key_sz != req->src_len)
+                       goto free_all;
+
+               copied = sg_copy_to_buffer(req->src,
+                                          sg_nents_for_len(req->src,
+                                                           public_key_sz),
+                                          public_key, public_key_sz);
+               if (copied != public_key_sz)
                        goto free_all;
-               }
 
                ret = crypto_ecdh_shared_secret(ctx->curve_id, ctx->ndigits,
                                                ctx->private_key, public_key,
@@ -111,7 +118,11 @@ static int ecdh_compute_value(struct kpp_request *req)
        if (ret < 0)
                goto free_all;
 
-       copied = sg_copy_from_buffer(req->dst, 1, buf, nbytes);
+       /* might want less than we've got */
+       nbytes = min_t(size_t, nbytes, req->dst_len);
+       copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst,
+                                                               nbytes),
+                                    buf, nbytes);
        if (copied != nbytes)
                ret = -EINVAL;