The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/lib/digsig.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 3398cffd9677d080ef2f78db615ecf9c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.