linux/crypto/asymmetric_keys/public_key.c
<<
>>
Prefs
   1/* In-software asymmetric public-key crypto subtype
   2 *
   3 * See Documentation/crypto/asymmetric-keys.txt
   4 *
   5 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
   6 * Written by David Howells (dhowells@redhat.com)
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public Licence
  10 * as published by the Free Software Foundation; either version
  11 * 2 of the Licence, or (at your option) any later version.
  12 */
  13
  14#define pr_fmt(fmt) "PKEY: "fmt
  15#include <linux/module.h>
  16#include <linux/export.h>
  17#include <linux/kernel.h>
  18#include <linux/slab.h>
  19#include <linux/seq_file.h>
  20#include <linux/scatterlist.h>
  21#include <keys/asymmetric-subtype.h>
  22#include <crypto/public_key.h>
  23#include <crypto/akcipher.h>
  24
  25MODULE_LICENSE("GPL");
  26
  27/*
  28 * Provide a part of a description of the key for /proc/keys.
  29 */
  30static void public_key_describe(const struct key *asymmetric_key,
  31                                struct seq_file *m)
  32{
  33        struct public_key *key = asymmetric_key->payload.data[asym_crypto];
  34
  35        if (key)
  36                seq_printf(m, "%s.%s", key->id_type, key->pkey_algo);
  37}
  38
  39/*
  40 * Destroy a public key algorithm key.
  41 */
  42void public_key_free(struct public_key *key)
  43{
  44        if (key) {
  45                kfree(key->key);
  46                kfree(key);
  47        }
  48}
  49EXPORT_SYMBOL_GPL(public_key_free);
  50
  51/*
  52 * Destroy a public key algorithm key.
  53 */
  54static void public_key_destroy(void *payload0, void *payload3)
  55{
  56        public_key_free(payload0);
  57        public_key_signature_free(payload3);
  58}
  59
  60struct public_key_completion {
  61        struct completion completion;
  62        int err;
  63};
  64
  65static void public_key_verify_done(struct crypto_async_request *req, int err)
  66{
  67        struct public_key_completion *compl = req->data;
  68
  69        if (err == -EINPROGRESS)
  70                return;
  71
  72        compl->err = err;
  73        complete(&compl->completion);
  74}
  75
  76/*
  77 * Verify a signature using a public key.
  78 */
  79int public_key_verify_signature(const struct public_key *pkey,
  80                                const struct public_key_signature *sig)
  81{
  82        struct public_key_completion compl;
  83        struct crypto_akcipher *tfm;
  84        struct akcipher_request *req;
  85        struct scatterlist sig_sg, digest_sg;
  86        const char *alg_name;
  87        char alg_name_buf[CRYPTO_MAX_ALG_NAME];
  88        void *output;
  89        unsigned int outlen;
  90        int ret = -ENOMEM;
  91
  92        pr_devel("==>%s()\n", __func__);
  93
  94        BUG_ON(!pkey);
  95        BUG_ON(!sig);
  96        BUG_ON(!sig->digest);
  97        BUG_ON(!sig->s);
  98
  99        alg_name = sig->pkey_algo;
 100        if (strcmp(sig->pkey_algo, "rsa") == 0) {
 101                /* The data wangled by the RSA algorithm is typically padded
 102                 * and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447
 103                 * sec 8.2].
 104                 */
 105                if (snprintf(alg_name_buf, CRYPTO_MAX_ALG_NAME,
 106                             "pkcs1pad(rsa,%s)", sig->hash_algo
 107                             ) >= CRYPTO_MAX_ALG_NAME)
 108                        return -EINVAL;
 109                alg_name = alg_name_buf;
 110        }
 111
 112        tfm = crypto_alloc_akcipher(alg_name, 0, 0);
 113        if (IS_ERR(tfm))
 114                return PTR_ERR(tfm);
 115
 116        req = akcipher_request_alloc(tfm, GFP_KERNEL);
 117        if (!req)
 118                goto error_free_tfm;
 119
 120        ret = crypto_akcipher_set_pub_key(tfm, pkey->key, pkey->keylen);
 121        if (ret)
 122                goto error_free_req;
 123
 124        outlen = crypto_akcipher_maxsize(tfm);
 125        output = kmalloc(outlen, GFP_KERNEL);
 126        if (!output)
 127                goto error_free_req;
 128
 129        sg_init_one(&sig_sg, sig->s, sig->s_size);
 130        sg_init_one(&digest_sg, output, outlen);
 131        akcipher_request_set_crypt(req, &sig_sg, &digest_sg, sig->s_size,
 132                                   outlen);
 133        init_completion(&compl.completion);
 134        akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
 135                                      CRYPTO_TFM_REQ_MAY_SLEEP,
 136                                      public_key_verify_done, &compl);
 137
 138        /* Perform the verification calculation.  This doesn't actually do the
 139         * verification, but rather calculates the hash expected by the
 140         * signature and returns that to us.
 141         */
 142        ret = crypto_akcipher_verify(req);
 143        if (ret == -EINPROGRESS) {
 144                wait_for_completion(&compl.completion);
 145                ret = compl.err;
 146        }
 147        if (ret < 0)
 148                goto out_free_output;
 149
 150        /* Do the actual verification step. */
 151        if (req->dst_len != sig->digest_size ||
 152            memcmp(sig->digest, output, sig->digest_size) != 0)
 153                ret = -EKEYREJECTED;
 154
 155out_free_output:
 156        kfree(output);
 157error_free_req:
 158        akcipher_request_free(req);
 159error_free_tfm:
 160        crypto_free_akcipher(tfm);
 161        pr_devel("<==%s() = %d\n", __func__, ret);
 162        return ret;
 163}
 164EXPORT_SYMBOL_GPL(public_key_verify_signature);
 165
 166static int public_key_verify_signature_2(const struct key *key,
 167                                         const struct public_key_signature *sig)
 168{
 169        const struct public_key *pk = key->payload.data[asym_crypto];
 170        return public_key_verify_signature(pk, sig);
 171}
 172
 173/*
 174 * Public key algorithm asymmetric key subtype
 175 */
 176struct asymmetric_key_subtype public_key_subtype = {
 177        .owner                  = THIS_MODULE,
 178        .name                   = "public_key",
 179        .name_len               = sizeof("public_key") - 1,
 180        .describe               = public_key_describe,
 181        .destroy                = public_key_destroy,
 182        .verify_signature       = public_key_verify_signature_2,
 183};
 184EXPORT_SYMBOL_GPL(public_key_subtype);
 185