linux/security/keys/dh.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* Crypto operations using stored keys
   3 *
   4 * Copyright (c) 2016, Intel Corporation
   5 */
   6
   7#include <linux/slab.h>
   8#include <linux/uaccess.h>
   9#include <linux/scatterlist.h>
  10#include <linux/crypto.h>
  11#include <crypto/hash.h>
  12#include <crypto/kpp.h>
  13#include <crypto/dh.h>
  14#include <crypto/kdf_sp800108.h>
  15#include <keys/user-type.h>
  16#include "internal.h"
  17
  18static ssize_t dh_data_from_key(key_serial_t keyid, const void **data)
  19{
  20        struct key *key;
  21        key_ref_t key_ref;
  22        long status;
  23        ssize_t ret;
  24
  25        key_ref = lookup_user_key(keyid, 0, KEY_NEED_READ);
  26        if (IS_ERR(key_ref)) {
  27                ret = -ENOKEY;
  28                goto error;
  29        }
  30
  31        key = key_ref_to_ptr(key_ref);
  32
  33        ret = -EOPNOTSUPP;
  34        if (key->type == &key_type_user) {
  35                down_read(&key->sem);
  36                status = key_validate(key);
  37                if (status == 0) {
  38                        const struct user_key_payload *payload;
  39                        uint8_t *duplicate;
  40
  41                        payload = user_key_payload_locked(key);
  42
  43                        duplicate = kmemdup(payload->data, payload->datalen,
  44                                            GFP_KERNEL);
  45                        if (duplicate) {
  46                                *data = duplicate;
  47                                ret = payload->datalen;
  48                        } else {
  49                                ret = -ENOMEM;
  50                        }
  51                }
  52                up_read(&key->sem);
  53        }
  54
  55        key_put(key);
  56error:
  57        return ret;
  58}
  59
  60static void dh_free_data(struct dh *dh)
  61{
  62        kfree_sensitive(dh->key);
  63        kfree_sensitive(dh->p);
  64        kfree_sensitive(dh->g);
  65}
  66
  67struct dh_completion {
  68        struct completion completion;
  69        int err;
  70};
  71
  72static void dh_crypto_done(struct crypto_async_request *req, int err)
  73{
  74        struct dh_completion *compl = req->data;
  75
  76        if (err == -EINPROGRESS)
  77                return;
  78
  79        compl->err = err;
  80        complete(&compl->completion);
  81}
  82
  83static int kdf_alloc(struct crypto_shash **hash, char *hashname)
  84{
  85        struct crypto_shash *tfm;
  86
  87        /* allocate synchronous hash */
  88        tfm = crypto_alloc_shash(hashname, 0, 0);
  89        if (IS_ERR(tfm)) {
  90                pr_info("could not allocate digest TFM handle %s\n", hashname);
  91                return PTR_ERR(tfm);
  92        }
  93
  94        if (crypto_shash_digestsize(tfm) == 0) {
  95                crypto_free_shash(tfm);
  96                return -EINVAL;
  97        }
  98
  99        *hash = tfm;
 100
 101        return 0;
 102}
 103
 104static void kdf_dealloc(struct crypto_shash *hash)
 105{
 106        if (hash)
 107                crypto_free_shash(hash);
 108}
 109
 110static int keyctl_dh_compute_kdf(struct crypto_shash *hash,
 111                                 char __user *buffer, size_t buflen,
 112                                 uint8_t *kbuf, size_t kbuflen)
 113{
 114        struct kvec kbuf_iov = { .iov_base = kbuf, .iov_len = kbuflen };
 115        uint8_t *outbuf = NULL;
 116        int ret;
 117        size_t outbuf_len = roundup(buflen, crypto_shash_digestsize(hash));
 118
 119        outbuf = kmalloc(outbuf_len, GFP_KERNEL);
 120        if (!outbuf) {
 121                ret = -ENOMEM;
 122                goto err;
 123        }
 124
 125        ret = crypto_kdf108_ctr_generate(hash, &kbuf_iov, 1, outbuf, outbuf_len);
 126        if (ret)
 127                goto err;
 128
 129        ret = buflen;
 130        if (copy_to_user(buffer, outbuf, buflen) != 0)
 131                ret = -EFAULT;
 132
 133err:
 134        kfree_sensitive(outbuf);
 135        return ret;
 136}
 137
 138long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
 139                         char __user *buffer, size_t buflen,
 140                         struct keyctl_kdf_params *kdfcopy)
 141{
 142        long ret;
 143        ssize_t dlen;
 144        int secretlen;
 145        int outlen;
 146        struct keyctl_dh_params pcopy;
 147        struct dh dh_inputs;
 148        struct scatterlist outsg;
 149        struct dh_completion compl;
 150        struct crypto_kpp *tfm;
 151        struct kpp_request *req;
 152        uint8_t *secret;
 153        uint8_t *outbuf;
 154        struct crypto_shash *hash = NULL;
 155
 156        if (!params || (!buffer && buflen)) {
 157                ret = -EINVAL;
 158                goto out1;
 159        }
 160        if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) {
 161                ret = -EFAULT;
 162                goto out1;
 163        }
 164
 165        if (kdfcopy) {
 166                char *hashname;
 167
 168                if (memchr_inv(kdfcopy->__spare, 0, sizeof(kdfcopy->__spare))) {
 169                        ret = -EINVAL;
 170                        goto out1;
 171                }
 172
 173                if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN ||
 174                    kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) {
 175                        ret = -EMSGSIZE;
 176                        goto out1;
 177                }
 178
 179                /* get KDF name string */
 180                hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME);
 181                if (IS_ERR(hashname)) {
 182                        ret = PTR_ERR(hashname);
 183                        goto out1;
 184                }
 185
 186                /* allocate KDF from the kernel crypto API */
 187                ret = kdf_alloc(&hash, hashname);
 188                kfree(hashname);
 189                if (ret)
 190                        goto out1;
 191        }
 192
 193        memset(&dh_inputs, 0, sizeof(dh_inputs));
 194
 195        dlen = dh_data_from_key(pcopy.prime, &dh_inputs.p);
 196        if (dlen < 0) {
 197                ret = dlen;
 198                goto out1;
 199        }
 200        dh_inputs.p_size = dlen;
 201
 202        dlen = dh_data_from_key(pcopy.base, &dh_inputs.g);
 203        if (dlen < 0) {
 204                ret = dlen;
 205                goto out2;
 206        }
 207        dh_inputs.g_size = dlen;
 208
 209        dlen = dh_data_from_key(pcopy.private, &dh_inputs.key);
 210        if (dlen < 0) {
 211                ret = dlen;
 212                goto out2;
 213        }
 214        dh_inputs.key_size = dlen;
 215
 216        secretlen = crypto_dh_key_len(&dh_inputs);
 217        secret = kmalloc(secretlen, GFP_KERNEL);
 218        if (!secret) {
 219                ret = -ENOMEM;
 220                goto out2;
 221        }
 222        ret = crypto_dh_encode_key(secret, secretlen, &dh_inputs);
 223        if (ret)
 224                goto out3;
 225
 226        tfm = crypto_alloc_kpp("dh", 0, 0);
 227        if (IS_ERR(tfm)) {
 228                ret = PTR_ERR(tfm);
 229                goto out3;
 230        }
 231
 232        ret = crypto_kpp_set_secret(tfm, secret, secretlen);
 233        if (ret)
 234                goto out4;
 235
 236        outlen = crypto_kpp_maxsize(tfm);
 237
 238        if (!kdfcopy) {
 239                /*
 240                 * When not using a KDF, buflen 0 is used to read the
 241                 * required buffer length
 242                 */
 243                if (buflen == 0) {
 244                        ret = outlen;
 245                        goto out4;
 246                } else if (outlen > buflen) {
 247                        ret = -EOVERFLOW;
 248                        goto out4;
 249                }
 250        }
 251
 252        outbuf = kzalloc(kdfcopy ? (outlen + kdfcopy->otherinfolen) : outlen,
 253                         GFP_KERNEL);
 254        if (!outbuf) {
 255                ret = -ENOMEM;
 256                goto out4;
 257        }
 258
 259        sg_init_one(&outsg, outbuf, outlen);
 260
 261        req = kpp_request_alloc(tfm, GFP_KERNEL);
 262        if (!req) {
 263                ret = -ENOMEM;
 264                goto out5;
 265        }
 266
 267        kpp_request_set_input(req, NULL, 0);
 268        kpp_request_set_output(req, &outsg, outlen);
 269        init_completion(&compl.completion);
 270        kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
 271                                 CRYPTO_TFM_REQ_MAY_SLEEP,
 272                                 dh_crypto_done, &compl);
 273
 274        /*
 275         * For DH, generate_public_key and generate_shared_secret are
 276         * the same calculation
 277         */
 278        ret = crypto_kpp_generate_public_key(req);
 279        if (ret == -EINPROGRESS) {
 280                wait_for_completion(&compl.completion);
 281                ret = compl.err;
 282                if (ret)
 283                        goto out6;
 284        }
 285
 286        if (kdfcopy) {
 287                /*
 288                 * Concatenate SP800-56A otherinfo past DH shared secret -- the
 289                 * input to the KDF is (DH shared secret || otherinfo)
 290                 */
 291                if (copy_from_user(outbuf + req->dst_len, kdfcopy->otherinfo,
 292                                   kdfcopy->otherinfolen) != 0) {
 293                        ret = -EFAULT;
 294                        goto out6;
 295                }
 296
 297                ret = keyctl_dh_compute_kdf(hash, buffer, buflen, outbuf,
 298                                            req->dst_len + kdfcopy->otherinfolen);
 299        } else if (copy_to_user(buffer, outbuf, req->dst_len) == 0) {
 300                ret = req->dst_len;
 301        } else {
 302                ret = -EFAULT;
 303        }
 304
 305out6:
 306        kpp_request_free(req);
 307out5:
 308        kfree_sensitive(outbuf);
 309out4:
 310        crypto_free_kpp(tfm);
 311out3:
 312        kfree_sensitive(secret);
 313out2:
 314        dh_free_data(&dh_inputs);
 315out1:
 316        kdf_dealloc(hash);
 317        return ret;
 318}
 319
 320long keyctl_dh_compute(struct keyctl_dh_params __user *params,
 321                       char __user *buffer, size_t buflen,
 322                       struct keyctl_kdf_params __user *kdf)
 323{
 324        struct keyctl_kdf_params kdfcopy;
 325
 326        if (!kdf)
 327                return __keyctl_dh_compute(params, buffer, buflen, NULL);
 328
 329        if (copy_from_user(&kdfcopy, kdf, sizeof(kdfcopy)) != 0)
 330                return -EFAULT;
 331
 332        return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy);
 333}
 334