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,
        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;