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_destroy(void *payload)
  43{
  44        struct public_key *key = payload;
  45
  46        if (key)
  47                kfree(key->key);
  48        kfree(key);
  49}
  50EXPORT_SYMBOL_GPL(public_key_destroy);
  51
  52struct public_key_completion {
  53        struct completion completion;
  54        int err;
  55};
  56
  57static void public_key_verify_done(struct crypto_async_request *req, int err)
  58{
  59        struct public_key_completion *compl = req->data;
  60
  61        if (err == -EINPROGRESS)
  62                return;
  63
  64        compl->err = err;
  65        complete(&compl->completion);
  66}
  67
  68/*
  69 * Verify a signature using a public key.
  70 */
  71int public_key_verify_signature(const struct public_key *pkey,
  72                                const struct public_key_signature *sig)
  73{
  74        struct public_key_completion compl;
  75        struct crypto_akcipher *tfm;
  76        struct akcipher_request *req;
  77        struct scatterlist sig_sg, digest_sg;
  78        const char *alg_name;
  79        char alg_name_buf[CRYPTO_MAX_ALG_NAME];
  80        void *output;
  81        unsigned int outlen;
  82        int ret = -ENOMEM;
  83
  84        pr_devel("==>%s()\n", __func__);
  85
  86        BUG_ON(!pkey);
  87        BUG_ON(!sig);
  88        BUG_ON(!sig->digest);
  89        BUG_ON(!sig->s);
  90
  91        alg_name = sig->pkey_algo;
  92        if (strcmp(sig->pkey_algo, "rsa") == 0) {
  93                /* The data wangled by the RSA algorithm is typically padded
  94                 * and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447
  95                 * sec 8.2].
  96                 */
  97                if (snprintf(alg_name_buf, CRYPTO_MAX_ALG_NAME,
  98                             "pkcs1pad(rsa,%s)", sig->hash_algo
  99                             ) >= CRYPTO_MAX_ALG_NAME)
 100                        return -EINVAL;
 101                alg_name = alg_name_buf;
 102        }
 103
 104        tfm = crypto_alloc_akcipher(alg_name, 0, 0);
 105        if (IS_ERR(tfm))
 106                return PTR_ERR(tfm);
 107
 108        req = akcipher_request_alloc(tfm, GFP_KERNEL);
 109        if (!req)
 110                goto error_free_tfm;
 111
 112        ret = crypto_akcipher_set_pub_key(tfm, pkey->key, pkey->keylen);
 113        if (ret)
 114                goto error_free_req;
 115
 116        outlen = crypto_akcipher_maxsize(tfm);
 117        output = kmalloc(outlen, GFP_KERNEL);
 118        if (!output)
 119                goto error_free_req;
 120
 121        sg_init_one(&sig_sg, sig->s, sig->s_size);
 122        sg_init_one(&digest_sg, output, outlen);
 123        akcipher_request_set_crypt(req, &sig_sg, &digest_sg, sig->s_size,
 124                                   outlen);
 125        init_completion(&compl.completion);
 126        akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
 127                                      CRYPTO_TFM_REQ_MAY_SLEEP,
 128                                      public_key_verify_done, &compl);
 129
 130        /* Perform the verification calculation.  This doesn't actually do the
 131         * verification, but rather calculates the hash expected by the
 132         * signature and returns that to us.
 133         */
 134        ret = crypto_akcipher_verify(req);
 135        if (ret == -EINPROGRESS) {
 136                wait_for_completion(&compl.completion);
 137                ret = compl.err;
 138        }
 139        if (ret < 0)
 140                goto out_free_output;
 141
 142        /* Do the actual verification step. */
 143        if (req->dst_len != sig->digest_size ||
 144            memcmp(sig->digest, output, sig->digest_size) != 0)
 145                ret = -EKEYREJECTED;
 146
 147out_free_output:
 148        kfree(output);
 149error_free_req:
 150        akcipher_request_free(req);
 151error_free_tfm:
 152        crypto_free_akcipher(tfm);
 153        pr_devel("<==%s() = %d\n", __func__, ret);
 154        return ret;
 155}
 156EXPORT_SYMBOL_GPL(public_key_verify_signature);
 157
 158static int public_key_verify_signature_2(const struct key *key,
 159                                         const struct public_key_signature *sig)
 160{
 161        const struct public_key *pk = key->payload.data[asym_crypto];
 162        return public_key_verify_signature(pk, sig);
 163}
 164
 165/*
 166 * Public key algorithm asymmetric key subtype
 167 */
 168struct asymmetric_key_subtype public_key_subtype = {
 169        .owner                  = THIS_MODULE,
 170        .name                   = "public_key",
 171        .name_len               = sizeof("public_key") - 1,
 172        .describe               = public_key_describe,
 173        .destroy                = public_key_destroy,
 174        .verify_signature       = public_key_verify_signature_2,
 175};
 176EXPORT_SYMBOL_GPL(public_key_subtype);
 177