Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* ECDH key-agreement protocol
0003  *
0004  * Copyright (c) 2016, Intel Corporation
0005  * Authors: Salvator Benedetto <salvatore.benedetto@intel.com>
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <crypto/internal/ecc.h>
0010 #include <crypto/internal/kpp.h>
0011 #include <crypto/kpp.h>
0012 #include <crypto/ecdh.h>
0013 #include <linux/scatterlist.h>
0014 
0015 struct ecdh_ctx {
0016     unsigned int curve_id;
0017     unsigned int ndigits;
0018     u64 private_key[ECC_MAX_DIGITS];
0019 };
0020 
0021 static inline struct ecdh_ctx *ecdh_get_ctx(struct crypto_kpp *tfm)
0022 {
0023     return kpp_tfm_ctx(tfm);
0024 }
0025 
0026 static int ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
0027                unsigned int len)
0028 {
0029     struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
0030     struct ecdh params;
0031 
0032     if (crypto_ecdh_decode_key(buf, len, &params) < 0 ||
0033         params.key_size > sizeof(u64) * ctx->ndigits)
0034         return -EINVAL;
0035 
0036     if (!params.key || !params.key_size)
0037         return ecc_gen_privkey(ctx->curve_id, ctx->ndigits,
0038                        ctx->private_key);
0039 
0040     memcpy(ctx->private_key, params.key, params.key_size);
0041 
0042     if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits,
0043                  ctx->private_key, params.key_size) < 0) {
0044         memzero_explicit(ctx->private_key, params.key_size);
0045         return -EINVAL;
0046     }
0047     return 0;
0048 }
0049 
0050 static int ecdh_compute_value(struct kpp_request *req)
0051 {
0052     struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
0053     struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
0054     u64 *public_key;
0055     u64 *shared_secret = NULL;
0056     void *buf;
0057     size_t copied, nbytes, public_key_sz;
0058     int ret = -ENOMEM;
0059 
0060     nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT;
0061     /* Public part is a point thus it has both coordinates */
0062     public_key_sz = 2 * nbytes;
0063 
0064     public_key = kmalloc(public_key_sz, GFP_KERNEL);
0065     if (!public_key)
0066         return -ENOMEM;
0067 
0068     if (req->src) {
0069         shared_secret = kmalloc(nbytes, GFP_KERNEL);
0070         if (!shared_secret)
0071             goto free_pubkey;
0072 
0073         /* from here on it's invalid parameters */
0074         ret = -EINVAL;
0075 
0076         /* must have exactly two points to be on the curve */
0077         if (public_key_sz != req->src_len)
0078             goto free_all;
0079 
0080         copied = sg_copy_to_buffer(req->src,
0081                        sg_nents_for_len(req->src,
0082                                 public_key_sz),
0083                        public_key, public_key_sz);
0084         if (copied != public_key_sz)
0085             goto free_all;
0086 
0087         ret = crypto_ecdh_shared_secret(ctx->curve_id, ctx->ndigits,
0088                         ctx->private_key, public_key,
0089                         shared_secret);
0090 
0091         buf = shared_secret;
0092     } else {
0093         ret = ecc_make_pub_key(ctx->curve_id, ctx->ndigits,
0094                        ctx->private_key, public_key);
0095         buf = public_key;
0096         nbytes = public_key_sz;
0097     }
0098 
0099     if (ret < 0)
0100         goto free_all;
0101 
0102     /* might want less than we've got */
0103     nbytes = min_t(size_t, nbytes, req->dst_len);
0104     copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst,
0105                                 nbytes),
0106                      buf, nbytes);
0107     if (copied != nbytes)
0108         ret = -EINVAL;
0109 
0110     /* fall through */
0111 free_all:
0112     kfree_sensitive(shared_secret);
0113 free_pubkey:
0114     kfree(public_key);
0115     return ret;
0116 }
0117 
0118 static unsigned int ecdh_max_size(struct crypto_kpp *tfm)
0119 {
0120     struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
0121 
0122     /* Public key is made of two coordinates, add one to the left shift */
0123     return ctx->ndigits << (ECC_DIGITS_TO_BYTES_SHIFT + 1);
0124 }
0125 
0126 static int ecdh_nist_p192_init_tfm(struct crypto_kpp *tfm)
0127 {
0128     struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
0129 
0130     ctx->curve_id = ECC_CURVE_NIST_P192;
0131     ctx->ndigits = ECC_CURVE_NIST_P192_DIGITS;
0132 
0133     return 0;
0134 }
0135 
0136 static struct kpp_alg ecdh_nist_p192 = {
0137     .set_secret = ecdh_set_secret,
0138     .generate_public_key = ecdh_compute_value,
0139     .compute_shared_secret = ecdh_compute_value,
0140     .max_size = ecdh_max_size,
0141     .init = ecdh_nist_p192_init_tfm,
0142     .base = {
0143         .cra_name = "ecdh-nist-p192",
0144         .cra_driver_name = "ecdh-nist-p192-generic",
0145         .cra_priority = 100,
0146         .cra_module = THIS_MODULE,
0147         .cra_ctxsize = sizeof(struct ecdh_ctx),
0148     },
0149 };
0150 
0151 static int ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm)
0152 {
0153     struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
0154 
0155     ctx->curve_id = ECC_CURVE_NIST_P256;
0156     ctx->ndigits = ECC_CURVE_NIST_P256_DIGITS;
0157 
0158     return 0;
0159 }
0160 
0161 static struct kpp_alg ecdh_nist_p256 = {
0162     .set_secret = ecdh_set_secret,
0163     .generate_public_key = ecdh_compute_value,
0164     .compute_shared_secret = ecdh_compute_value,
0165     .max_size = ecdh_max_size,
0166     .init = ecdh_nist_p256_init_tfm,
0167     .base = {
0168         .cra_name = "ecdh-nist-p256",
0169         .cra_driver_name = "ecdh-nist-p256-generic",
0170         .cra_priority = 100,
0171         .cra_module = THIS_MODULE,
0172         .cra_ctxsize = sizeof(struct ecdh_ctx),
0173     },
0174 };
0175 
0176 static int ecdh_nist_p384_init_tfm(struct crypto_kpp *tfm)
0177 {
0178     struct ecdh_ctx *ctx = ecdh_get_ctx(tfm);
0179 
0180     ctx->curve_id = ECC_CURVE_NIST_P384;
0181     ctx->ndigits = ECC_CURVE_NIST_P384_DIGITS;
0182 
0183     return 0;
0184 }
0185 
0186 static struct kpp_alg ecdh_nist_p384 = {
0187     .set_secret = ecdh_set_secret,
0188     .generate_public_key = ecdh_compute_value,
0189     .compute_shared_secret = ecdh_compute_value,
0190     .max_size = ecdh_max_size,
0191     .init = ecdh_nist_p384_init_tfm,
0192     .base = {
0193         .cra_name = "ecdh-nist-p384",
0194         .cra_driver_name = "ecdh-nist-p384-generic",
0195         .cra_priority = 100,
0196         .cra_module = THIS_MODULE,
0197         .cra_ctxsize = sizeof(struct ecdh_ctx),
0198     },
0199 };
0200 
0201 static bool ecdh_nist_p192_registered;
0202 
0203 static int ecdh_init(void)
0204 {
0205     int ret;
0206 
0207     /* NIST p192 will fail to register in FIPS mode */
0208     ret = crypto_register_kpp(&ecdh_nist_p192);
0209     ecdh_nist_p192_registered = ret == 0;
0210 
0211     ret = crypto_register_kpp(&ecdh_nist_p256);
0212     if (ret)
0213         goto nist_p256_error;
0214 
0215     ret = crypto_register_kpp(&ecdh_nist_p384);
0216     if (ret)
0217         goto nist_p384_error;
0218 
0219     return 0;
0220 
0221 nist_p384_error:
0222     crypto_unregister_kpp(&ecdh_nist_p256);
0223 
0224 nist_p256_error:
0225     if (ecdh_nist_p192_registered)
0226         crypto_unregister_kpp(&ecdh_nist_p192);
0227     return ret;
0228 }
0229 
0230 static void ecdh_exit(void)
0231 {
0232     if (ecdh_nist_p192_registered)
0233         crypto_unregister_kpp(&ecdh_nist_p192);
0234     crypto_unregister_kpp(&ecdh_nist_p256);
0235     crypto_unregister_kpp(&ecdh_nist_p384);
0236 }
0237 
0238 subsys_initcall(ecdh_init);
0239 module_exit(ecdh_exit);
0240 MODULE_ALIAS_CRYPTO("ecdh");
0241 MODULE_LICENSE("GPL");
0242 MODULE_DESCRIPTION("ECDH generic algorithm");