linux/crypto/dh.c
<<
>>
Prefs
   1/*  Diffie-Hellman Key Agreement Method [RFC2631]
   2 *
   3 * Copyright (c) 2016, Intel Corporation
   4 * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com>
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the License, or (at your option) any later version.
  10 */
  11
  12#include <linux/module.h>
  13#include <crypto/internal/kpp.h>
  14#include <crypto/kpp.h>
  15#include <crypto/dh.h>
  16#include <linux/fips.h>
  17#include <linux/mpi.h>
  18
  19struct dh_ctx {
  20        MPI p;  /* Value is guaranteed to be set. */
  21        MPI q;  /* Value is optional. */
  22        MPI g;  /* Value is guaranteed to be set. */
  23        MPI xa; /* Value is guaranteed to be set. */
  24};
  25
  26static void dh_clear_ctx(struct dh_ctx *ctx)
  27{
  28        mpi_free(ctx->p);
  29        mpi_free(ctx->q);
  30        mpi_free(ctx->g);
  31        mpi_free(ctx->xa);
  32        memset(ctx, 0, sizeof(*ctx));
  33}
  34
  35/*
  36 * If base is g we compute the public key
  37 *      ya = g^xa mod p; [RFC2631 sec 2.1.1]
  38 * else if base if the counterpart public key we compute the shared secret
  39 *      ZZ = yb^xa mod p; [RFC2631 sec 2.1.1]
  40 */
  41static int _compute_val(const struct dh_ctx *ctx, MPI base, MPI val)
  42{
  43        /* val = base^xa mod p */
  44        return mpi_powm(val, base, ctx->xa, ctx->p);
  45}
  46
  47static inline struct dh_ctx *dh_get_ctx(struct crypto_kpp *tfm)
  48{
  49        return kpp_tfm_ctx(tfm);
  50}
  51
  52static int dh_check_params_length(unsigned int p_len)
  53{
  54        return (p_len < 1536) ? -EINVAL : 0;
  55}
  56
  57static int dh_set_params(struct dh_ctx *ctx, struct dh *params)
  58{
  59        if (dh_check_params_length(params->p_size << 3))
  60                return -EINVAL;
  61
  62        ctx->p = mpi_read_raw_data(params->p, params->p_size);
  63        if (!ctx->p)
  64                return -EINVAL;
  65
  66        if (params->q && params->q_size) {
  67                ctx->q = mpi_read_raw_data(params->q, params->q_size);
  68                if (!ctx->q)
  69                        return -EINVAL;
  70        }
  71
  72        ctx->g = mpi_read_raw_data(params->g, params->g_size);
  73        if (!ctx->g)
  74                return -EINVAL;
  75
  76        return 0;
  77}
  78
  79static int dh_set_secret(struct crypto_kpp *tfm, const void *buf,
  80                         unsigned int len)
  81{
  82        struct dh_ctx *ctx = dh_get_ctx(tfm);
  83        struct dh params;
  84
  85        /* Free the old MPI key if any */
  86        dh_clear_ctx(ctx);
  87
  88        if (crypto_dh_decode_key(buf, len, &params) < 0)
  89                goto err_clear_ctx;
  90
  91        if (dh_set_params(ctx, &params) < 0)
  92                goto err_clear_ctx;
  93
  94        ctx->xa = mpi_read_raw_data(params.key, params.key_size);
  95        if (!ctx->xa)
  96                goto err_clear_ctx;
  97
  98        return 0;
  99
 100err_clear_ctx:
 101        dh_clear_ctx(ctx);
 102        return -EINVAL;
 103}
 104
 105/*
 106 * SP800-56A public key verification:
 107 *
 108 * * If Q is provided as part of the domain paramenters, a full validation
 109 *   according to SP800-56A section 5.6.2.3.1 is performed.
 110 *
 111 * * If Q is not provided, a partial validation according to SP800-56A section
 112 *   5.6.2.3.2 is performed.
 113 */
 114static int dh_is_pubkey_valid(struct dh_ctx *ctx, MPI y)
 115{
 116        if (unlikely(!ctx->p))
 117                return -EINVAL;
 118
 119        /*
 120         * Step 1: Verify that 2 <= y <= p - 2.
 121         *
 122         * The upper limit check is actually y < p instead of y < p - 1
 123         * as the mpi_sub_ui function is yet missing.
 124         */
 125        if (mpi_cmp_ui(y, 1) < 1 || mpi_cmp(y, ctx->p) >= 0)
 126                return -EINVAL;
 127
 128        /* Step 2: Verify that 1 = y^q mod p */
 129        if (ctx->q) {
 130                MPI val = mpi_alloc(0);
 131                int ret;
 132
 133                if (!val)
 134                        return -ENOMEM;
 135
 136                ret = mpi_powm(val, y, ctx->q, ctx->p);
 137
 138                if (ret) {
 139                        mpi_free(val);
 140                        return ret;
 141                }
 142
 143                ret = mpi_cmp_ui(val, 1);
 144
 145                mpi_free(val);
 146
 147                if (ret != 0)
 148                        return -EINVAL;
 149        }
 150
 151        return 0;
 152}
 153
 154static int dh_compute_value(struct kpp_request *req)
 155{
 156        struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
 157        struct dh_ctx *ctx = dh_get_ctx(tfm);
 158        MPI base, val = mpi_alloc(0);
 159        int ret = 0;
 160        int sign;
 161
 162        if (!val)
 163                return -ENOMEM;
 164
 165        if (unlikely(!ctx->xa)) {
 166                ret = -EINVAL;
 167                goto err_free_val;
 168        }
 169
 170        if (req->src) {
 171                base = mpi_read_raw_from_sgl(req->src, req->src_len);
 172                if (!base) {
 173                        ret = -EINVAL;
 174                        goto err_free_val;
 175                }
 176                ret = dh_is_pubkey_valid(ctx, base);
 177                if (ret)
 178                        goto err_free_base;
 179        } else {
 180                base = ctx->g;
 181        }
 182
 183        ret = _compute_val(ctx, base, val);
 184        if (ret)
 185                goto err_free_base;
 186
 187        if (fips_enabled) {
 188                /* SP800-56A rev3 5.7.1.1 check: Validation of shared secret */
 189                if (req->src) {
 190                        MPI pone;
 191
 192                        /* z <= 1 */
 193                        if (mpi_cmp_ui(val, 1) < 1) {
 194                                ret = -EBADMSG;
 195                                goto err_free_base;
 196                        }
 197
 198                        /* z == p - 1 */
 199                        pone = mpi_alloc(0);
 200
 201                        if (!pone) {
 202                                ret = -ENOMEM;
 203                                goto err_free_base;
 204                        }
 205
 206                        ret = mpi_sub_ui(pone, ctx->p, 1);
 207                        if (!ret && !mpi_cmp(pone, val))
 208                                ret = -EBADMSG;
 209
 210                        mpi_free(pone);
 211
 212                        if (ret)
 213                                goto err_free_base;
 214
 215                /* SP800-56A rev 3 5.6.2.1.3 key check */
 216                } else {
 217                        if (dh_is_pubkey_valid(ctx, val)) {
 218                                ret = -EAGAIN;
 219                                goto err_free_val;
 220                        }
 221                }
 222        }
 223
 224        ret = mpi_write_to_sgl(val, req->dst, req->dst_len, &sign);
 225        if (ret)
 226                goto err_free_base;
 227
 228        if (sign < 0)
 229                ret = -EBADMSG;
 230err_free_base:
 231        if (req->src)
 232                mpi_free(base);
 233err_free_val:
 234        mpi_free(val);
 235        return ret;
 236}
 237
 238static unsigned int dh_max_size(struct crypto_kpp *tfm)
 239{
 240        struct dh_ctx *ctx = dh_get_ctx(tfm);
 241
 242        return mpi_get_size(ctx->p);
 243}
 244
 245static void dh_exit_tfm(struct crypto_kpp *tfm)
 246{
 247        struct dh_ctx *ctx = dh_get_ctx(tfm);
 248
 249        dh_clear_ctx(ctx);
 250}
 251
 252static struct kpp_alg dh = {
 253        .set_secret = dh_set_secret,
 254        .generate_public_key = dh_compute_value,
 255        .compute_shared_secret = dh_compute_value,
 256        .max_size = dh_max_size,
 257        .exit = dh_exit_tfm,
 258        .base = {
 259                .cra_name = "dh",
 260                .cra_driver_name = "dh-generic",
 261                .cra_priority = 100,
 262                .cra_module = THIS_MODULE,
 263                .cra_ctxsize = sizeof(struct dh_ctx),
 264        },
 265};
 266
 267static int dh_init(void)
 268{
 269        return crypto_register_kpp(&dh);
 270}
 271
 272static void dh_exit(void)
 273{
 274        crypto_unregister_kpp(&dh);
 275}
 276
 277module_init(dh_init);
 278module_exit(dh_exit);
 279MODULE_ALIAS_CRYPTO("dh");
 280MODULE_LICENSE("GPL");
 281MODULE_DESCRIPTION("DH generic algorithm");
 282