linux/lib/digsig.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2011 Nokia Corporation
   4 * Copyright (C) 2011 Intel Corporation
   5 *
   6 * Author:
   7 * Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
   8 *                 <dmitry.kasatkin@intel.com>
   9 *
  10 * File: sign.c
  11 *      implements signature (RSA) verification
  12 *      pkcs decoding is based on LibTomCrypt code
  13 */
  14
  15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  16
  17#include <linux/err.h>
  18#include <linux/module.h>
  19#include <linux/slab.h>
  20#include <linux/key.h>
  21#include <linux/crypto.h>
  22#include <crypto/hash.h>
  23#include <crypto/sha1.h>
  24#include <keys/user-type.h>
  25#include <linux/mpi.h>
  26#include <linux/digsig.h>
  27
  28static struct crypto_shash *shash;
  29
  30static const char *pkcs_1_v1_5_decode_emsa(const unsigned char *msg,
  31                                                unsigned long  msglen,
  32                                                unsigned long  modulus_bitlen,
  33                                                unsigned long *outlen)
  34{
  35        unsigned long modulus_len, ps_len, i;
  36
  37        modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
  38
  39        /* test message size */
  40        if ((msglen > modulus_len) || (modulus_len < 11))
  41                return NULL;
  42
  43        /* separate encoded message */
  44        if (msg[0] != 0x00 || msg[1] != 0x01)
  45                return NULL;
  46
  47        for (i = 2; i < modulus_len - 1; i++)
  48                if (msg[i] != 0xFF)
  49                        break;
  50
  51        /* separator check */
  52        if (msg[i] != 0)
  53                /* There was no octet with hexadecimal value 0x00
  54                to separate ps from m. */
  55                return NULL;
  56
  57        ps_len = i - 2;
  58
  59        *outlen = (msglen - (2 + ps_len + 1));
  60
  61        return msg + 2 + ps_len + 1;
  62}
  63
  64/*
  65 * RSA Signature verification with public key
  66 */
  67static int digsig_verify_rsa(struct key *key,
  68                    const char *sig, int siglen,
  69                       const char *h, int hlen)
  70{
  71        int err = -EINVAL;
  72        unsigned long len;
  73        unsigned long mlen, mblen;
  74        unsigned nret, l;
  75        int head, i;
  76        unsigned char *out1 = NULL;
  77        const char *m;
  78        MPI in = NULL, res = NULL, pkey[2];
  79        uint8_t *p, *datap;
  80        const uint8_t *endp;
  81        const struct user_key_payload *ukp;
  82        struct pubkey_hdr *pkh;
  83
  84        down_read(&key->sem);
  85        ukp = user_key_payload_locked(key);
  86
  87        if (!ukp) {
  88                /* key was revoked before we acquired its semaphore */
  89                err = -EKEYREVOKED;
  90                goto err1;
  91        }
  92
  93        if (ukp->datalen < sizeof(*pkh))
  94                goto err1;
  95
  96        pkh = (struct pubkey_hdr *)ukp->data;
  97
  98        if (pkh->version != 1)
  99                goto err1;
 100
 101        if (pkh->algo != PUBKEY_ALGO_RSA)
 102                goto err1;
 103
 104        if (pkh->nmpi != 2)
 105                goto err1;
 106
 107        datap = pkh->mpi;
 108        endp = ukp->data + ukp->datalen;
 109
 110        for (i = 0; i < pkh->nmpi; i++) {
 111                unsigned int remaining = endp - datap;
 112                pkey[i] = mpi_read_from_buffer(datap, &remaining);
 113                if (IS_ERR(pkey[i])) {
 114                        err = PTR_ERR(pkey[i]);
 115                        goto err;
 116                }
 117                datap += remaining;
 118        }
 119
 120        mblen = mpi_get_nbits(pkey[0]);
 121        mlen = DIV_ROUND_UP(mblen, 8);
 122
 123        if (mlen == 0) {
 124                err = -EINVAL;
 125                goto err;
 126        }
 127
 128        err = -ENOMEM;
 129
 130        out1 = kzalloc(mlen, GFP_KERNEL);
 131        if (!out1)
 132                goto err;
 133
 134        nret = siglen;
 135        in = mpi_read_from_buffer(sig, &nret);
 136        if (IS_ERR(in)) {
 137                err = PTR_ERR(in);
 138                goto err;
 139        }
 140
 141        res = mpi_alloc(mpi_get_nlimbs(in) * 2);
 142        if (!res)
 143                goto err;
 144
 145        err = mpi_powm(res, in, pkey[1], pkey[0]);
 146        if (err)
 147                goto err;
 148
 149        if (mpi_get_nlimbs(res) * BYTES_PER_MPI_LIMB > mlen) {
 150                err = -EINVAL;
 151                goto err;
 152        }
 153
 154        p = mpi_get_buffer(res, &l, NULL);
 155        if (!p) {
 156                err = -EINVAL;
 157                goto err;
 158        }
 159
 160        len = mlen;
 161        head = len - l;
 162        memset(out1, 0, head);
 163        memcpy(out1 + head, p, l);
 164
 165        kfree(p);
 166
 167        m = pkcs_1_v1_5_decode_emsa(out1, len, mblen, &len);
 168
 169        if (!m || len != hlen || memcmp(m, h, hlen))
 170                err = -EINVAL;
 171
 172err:
 173        mpi_free(in);
 174        mpi_free(res);
 175        kfree(out1);
 176        while (--i >= 0)
 177                mpi_free(pkey[i]);
 178err1:
 179        up_read(&key->sem);
 180
 181        return err;
 182}
 183
 184/**
 185 * digsig_verify() - digital signature verification with public key
 186 * @keyring:    keyring to search key in
 187 * @sig:        digital signature
 188 * @siglen:     length of the signature
 189 * @data:       data
 190 * @datalen:    length of the data
 191 *
 192 * Returns 0 on success, -EINVAL otherwise
 193 *
 194 * Verifies data integrity against digital signature.
 195 * Currently only RSA is supported.
 196 * Normally hash of the content is used as a data for this function.
 197 *
 198 */
 199int digsig_verify(struct key *keyring, const char *sig, int siglen,
 200                                                const char *data, int datalen)
 201{
 202        int err = -ENOMEM;
 203        struct signature_hdr *sh = (struct signature_hdr *)sig;
 204        struct shash_desc *desc = NULL;
 205        unsigned char hash[SHA1_DIGEST_SIZE];
 206        struct key *key;
 207        char name[20];
 208
 209        if (siglen < sizeof(*sh) + 2)
 210                return -EINVAL;
 211
 212        if (sh->algo != PUBKEY_ALGO_RSA)
 213                return -ENOTSUPP;
 214
 215        sprintf(name, "%llX", __be64_to_cpup((uint64_t *)sh->keyid));
 216
 217        if (keyring) {
 218                /* search in specific keyring */
 219                key_ref_t kref;
 220                kref = keyring_search(make_key_ref(keyring, 1UL),
 221                                      &key_type_user, name, true);
 222                if (IS_ERR(kref))
 223                        key = ERR_CAST(kref);
 224                else
 225                        key = key_ref_to_ptr(kref);
 226        } else {
 227                key = request_key(&key_type_user, name, NULL);
 228        }
 229        if (IS_ERR(key)) {
 230                pr_err("key not found, id: %s\n", name);
 231                return PTR_ERR(key);
 232        }
 233
 234        desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(shash),
 235                       GFP_KERNEL);
 236        if (!desc)
 237                goto err;
 238
 239        desc->tfm = shash;
 240
 241        crypto_shash_init(desc);
 242        crypto_shash_update(desc, data, datalen);
 243        crypto_shash_update(desc, sig, sizeof(*sh));
 244        crypto_shash_final(desc, hash);
 245
 246        kfree(desc);
 247
 248        /* pass signature mpis address */
 249        err = digsig_verify_rsa(key, sig + sizeof(*sh), siglen - sizeof(*sh),
 250                             hash, sizeof(hash));
 251
 252err:
 253        key_put(key);
 254
 255        return err ? -EINVAL : 0;
 256}
 257EXPORT_SYMBOL_GPL(digsig_verify);
 258
 259static int __init digsig_init(void)
 260{
 261        shash = crypto_alloc_shash("sha1", 0, 0);
 262        if (IS_ERR(shash)) {
 263                pr_err("shash allocation failed\n");
 264                return  PTR_ERR(shash);
 265        }
 266
 267        return 0;
 268
 269}
 270
 271static void __exit digsig_cleanup(void)
 272{
 273        crypto_free_shash(shash);
 274}
 275
 276module_init(digsig_init);
 277module_exit(digsig_cleanup);
 278
 279MODULE_LICENSE("GPL");
 280