linux/crypto/asymmetric_keys/x509_public_key.c
<<
>>
Prefs
   1/* Instantiate a public key crypto key from an X.509 Certificate
   2 *
   3 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public Licence
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the Licence, or (at your option) any later version.
  10 */
  11
  12#define pr_fmt(fmt) "X.509: "fmt
  13#include <linux/module.h>
  14#include <linux/kernel.h>
  15#include <linux/slab.h>
  16#include <linux/err.h>
  17#include <linux/mpi.h>
  18#include <linux/asn1_decoder.h>
  19#include <keys/asymmetric-subtype.h>
  20#include <keys/asymmetric-parser.h>
  21#include <crypto/hash.h>
  22#include "asymmetric_keys.h"
  23#include "public_key.h"
  24#include "x509_parser.h"
  25
  26static const
  27struct public_key_algorithm *x509_public_key_algorithms[PKEY_ALGO__LAST] = {
  28        [PKEY_ALGO_DSA]         = NULL,
  29#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \
  30        defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE)
  31        [PKEY_ALGO_RSA]         = &RSA_public_key_algorithm,
  32#endif
  33};
  34
  35/*
  36 * Check the signature on a certificate using the provided public key
  37 */
  38static int x509_check_signature(const struct public_key *pub,
  39                                const struct x509_certificate *cert)
  40{
  41        struct public_key_signature *sig;
  42        struct crypto_shash *tfm;
  43        struct shash_desc *desc;
  44        size_t digest_size, desc_size;
  45        int ret;
  46
  47        pr_devel("==>%s()\n", __func__);
  48        
  49        /* Allocate the hashing algorithm we're going to need and find out how
  50         * big the hash operational data will be.
  51         */
  52        tfm = crypto_alloc_shash(pkey_hash_algo[cert->sig_hash_algo], 0, 0);
  53        if (IS_ERR(tfm))
  54                return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
  55
  56        desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
  57        digest_size = crypto_shash_digestsize(tfm);
  58
  59        /* We allocate the hash operational data storage on the end of our
  60         * context data.
  61         */
  62        ret = -ENOMEM;
  63        sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL);
  64        if (!sig)
  65                goto error_no_sig;
  66
  67        sig->pkey_hash_algo     = cert->sig_hash_algo;
  68        sig->digest             = (u8 *)sig + sizeof(*sig) + desc_size;
  69        sig->digest_size        = digest_size;
  70
  71        desc = (void *)sig + sizeof(*sig);
  72        desc->tfm       = tfm;
  73        desc->flags     = CRYPTO_TFM_REQ_MAY_SLEEP;
  74
  75        ret = crypto_shash_init(desc);
  76        if (ret < 0)
  77                goto error;
  78
  79        ret = -ENOMEM;
  80        sig->rsa.s = mpi_read_raw_data(cert->sig, cert->sig_size);
  81        if (!sig->rsa.s)
  82                goto error;
  83
  84        ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest);
  85        if (ret < 0)
  86                goto error_mpi;
  87
  88        ret = pub->algo->verify_signature(pub, sig);
  89
  90        pr_debug("Cert Verification: %d\n", ret);
  91
  92error_mpi:
  93        mpi_free(sig->rsa.s);
  94error:
  95        kfree(sig);
  96error_no_sig:
  97        crypto_free_shash(tfm);
  98
  99        pr_devel("<==%s() = %d\n", __func__, ret);
 100        return ret;
 101}
 102
 103/*
 104 * Attempt to parse a data blob for a key as an X509 certificate.
 105 */
 106static int x509_key_preparse(struct key_preparsed_payload *prep)
 107{
 108        struct x509_certificate *cert;
 109        struct tm now;
 110        size_t srlen, sulen;
 111        char *desc = NULL;
 112        int ret;
 113
 114        cert = x509_cert_parse(prep->data, prep->datalen);
 115        if (IS_ERR(cert))
 116                return PTR_ERR(cert);
 117
 118        pr_devel("Cert Issuer: %s\n", cert->issuer);
 119        pr_devel("Cert Subject: %s\n", cert->subject);
 120        pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]);
 121        pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
 122                 cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
 123                 cert->valid_from.tm_mday, cert->valid_from.tm_hour,
 124                 cert->valid_from.tm_min,  cert->valid_from.tm_sec);
 125        pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n",
 126                 cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1,
 127                 cert->valid_to.tm_mday, cert->valid_to.tm_hour,
 128                 cert->valid_to.tm_min,  cert->valid_to.tm_sec);
 129        pr_devel("Cert Signature: %s + %s\n",
 130                 pkey_algo[cert->sig_pkey_algo],
 131                 pkey_hash_algo[cert->sig_hash_algo]);
 132
 133        if (!cert->fingerprint || !cert->authority) {
 134                pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n",
 135                        cert->subject);
 136                ret = -EKEYREJECTED;
 137                goto error_free_cert;
 138        }
 139
 140        time_to_tm(CURRENT_TIME.tv_sec, 0, &now);
 141        pr_devel("Now: %04ld-%02d-%02d %02d:%02d:%02d\n",
 142                 now.tm_year + 1900, now.tm_mon + 1, now.tm_mday,
 143                 now.tm_hour, now.tm_min,  now.tm_sec);
 144        if (now.tm_year < cert->valid_from.tm_year ||
 145            (now.tm_year == cert->valid_from.tm_year &&
 146             (now.tm_mon < cert->valid_from.tm_mon ||
 147              (now.tm_mon == cert->valid_from.tm_mon &&
 148               (now.tm_mday < cert->valid_from.tm_mday ||
 149                (now.tm_mday == cert->valid_from.tm_mday &&
 150                 (now.tm_hour < cert->valid_from.tm_hour ||
 151                  (now.tm_hour == cert->valid_from.tm_hour &&
 152                   (now.tm_min < cert->valid_from.tm_min ||
 153                    (now.tm_min == cert->valid_from.tm_min &&
 154                     (now.tm_sec < cert->valid_from.tm_sec
 155                      ))))))))))) {
 156                pr_warn("Cert %s is not yet valid\n", cert->fingerprint);
 157                ret = -EKEYREJECTED;
 158                goto error_free_cert;
 159        }
 160        if (now.tm_year > cert->valid_to.tm_year ||
 161            (now.tm_year == cert->valid_to.tm_year &&
 162             (now.tm_mon > cert->valid_to.tm_mon ||
 163              (now.tm_mon == cert->valid_to.tm_mon &&
 164               (now.tm_mday > cert->valid_to.tm_mday ||
 165                (now.tm_mday == cert->valid_to.tm_mday &&
 166                 (now.tm_hour > cert->valid_to.tm_hour ||
 167                  (now.tm_hour == cert->valid_to.tm_hour &&
 168                   (now.tm_min > cert->valid_to.tm_min ||
 169                    (now.tm_min == cert->valid_to.tm_min &&
 170                     (now.tm_sec > cert->valid_to.tm_sec
 171                      ))))))))))) {
 172                pr_warn("Cert %s has expired\n", cert->fingerprint);
 173                ret = -EKEYEXPIRED;
 174                goto error_free_cert;
 175        }
 176
 177        cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo];
 178        cert->pub->id_type = PKEY_ID_X509;
 179
 180        /* Check the signature on the key */
 181        if (strcmp(cert->fingerprint, cert->authority) == 0) {
 182                ret = x509_check_signature(cert->pub, cert);
 183                if (ret < 0)
 184                        goto error_free_cert;
 185        }
 186
 187        /* Propose a description */
 188        sulen = strlen(cert->subject);
 189        srlen = strlen(cert->fingerprint);
 190        ret = -ENOMEM;
 191        desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL);
 192        if (!desc)
 193                goto error_free_cert;
 194        memcpy(desc, cert->subject, sulen);
 195        desc[sulen] = ':';
 196        desc[sulen + 1] = ' ';
 197        memcpy(desc + sulen + 2, cert->fingerprint, srlen);
 198        desc[sulen + 2 + srlen] = 0;
 199
 200        /* We're pinning the module by being linked against it */
 201        __module_get(public_key_subtype.owner);
 202        prep->type_data[0] = &public_key_subtype;
 203        prep->type_data[1] = cert->fingerprint;
 204        prep->payload = cert->pub;
 205        prep->description = desc;
 206        prep->quotalen = 100;
 207
 208        /* We've finished with the certificate */
 209        cert->pub = NULL;
 210        cert->fingerprint = NULL;
 211        desc = NULL;
 212        ret = 0;
 213
 214error_free_cert:
 215        x509_free_certificate(cert);
 216        return ret;
 217}
 218
 219static struct asymmetric_key_parser x509_key_parser = {
 220        .owner  = THIS_MODULE,
 221        .name   = "x509",
 222        .parse  = x509_key_preparse,
 223};
 224
 225/*
 226 * Module stuff
 227 */
 228static int __init x509_key_init(void)
 229{
 230        return register_asymmetric_key_parser(&x509_key_parser);
 231}
 232
 233static void __exit x509_key_exit(void)
 234{
 235        unregister_asymmetric_key_parser(&x509_key_parser);
 236}
 237
 238module_init(x509_key_init);
 239module_exit(x509_key_exit);
 240
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.