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 <keys/asymmetric-subtype.h>
  17#include <keys/asymmetric-parser.h>
  18#include <keys/system_keyring.h>
  19#include <crypto/hash.h>
  20#include "asymmetric_keys.h"
  21#include "x509_parser.h"
  22
  23static bool use_builtin_keys;
  24static struct asymmetric_key_id *ca_keyid;
  25
  26#ifndef MODULE
  27static struct {
  28        struct asymmetric_key_id id;
  29        unsigned char data[10];
  30} cakey;
  31
  32static int __init ca_keys_setup(char *str)
  33{
  34        if (!str)               /* default system keyring */
  35                return 1;
  36
  37        if (strncmp(str, "id:", 3) == 0) {
  38                struct asymmetric_key_id *p = &cakey.id;
  39                size_t hexlen = (strlen(str) - 3) / 2;
  40                int ret;
  41
  42                if (hexlen == 0 || hexlen > sizeof(cakey.data)) {
  43                        pr_err("Missing or invalid ca_keys id\n");
  44                        return 1;
  45                }
  46
  47                ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen);
  48                if (ret < 0)
  49                        pr_err("Unparsable ca_keys id hex string\n");
  50                else
  51                        ca_keyid = p;   /* owner key 'id:xxxxxx' */
  52        } else if (strcmp(str, "builtin") == 0) {
  53                use_builtin_keys = true;
  54        }
  55
  56        return 1;
  57}
  58__setup("ca_keys=", ca_keys_setup);
  59#endif
  60
  61/**
  62 * x509_request_asymmetric_key - Request a key by X.509 certificate params.
  63 * @keyring: The keys to search.
  64 * @id: The issuer & serialNumber to look for or NULL.
  65 * @skid: The subjectKeyIdentifier to look for or NULL.
  66 * @partial: Use partial match if true, exact if false.
  67 *
  68 * Find a key in the given keyring by identifier.  The preferred identifier is
  69 * the issuer + serialNumber and the fallback identifier is the
  70 * subjectKeyIdentifier.  If both are given, the lookup is by the former, but
  71 * the latter must also match.
  72 */
  73struct key *x509_request_asymmetric_key(struct key *keyring,
  74                                        const struct asymmetric_key_id *id,
  75                                        const struct asymmetric_key_id *skid,
  76                                        bool partial)
  77{
  78        struct key *key;
  79        key_ref_t ref;
  80        const char *lookup;
  81        char *req, *p;
  82        int len;
  83
  84        if (id) {
  85                lookup = id->data;
  86                len = id->len;
  87        } else {
  88                lookup = skid->data;
  89                len = skid->len;
  90        }
  91        
  92        /* Construct an identifier "id:<keyid>". */
  93        p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
  94        if (!req)
  95                return ERR_PTR(-ENOMEM);
  96
  97        if (partial) {
  98                *p++ = 'i';
  99                *p++ = 'd';
 100        } else {
 101                *p++ = 'e';
 102                *p++ = 'x';
 103        }
 104        *p++ = ':';
 105        p = bin2hex(p, lookup, len);
 106        *p = 0;
 107
 108        pr_debug("Look up: \"%s\"\n", req);
 109
 110        ref = keyring_search(make_key_ref(keyring, 1),
 111                             &key_type_asymmetric, req);
 112        if (IS_ERR(ref))
 113                pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
 114        kfree(req);
 115
 116        if (IS_ERR(ref)) {
 117                switch (PTR_ERR(ref)) {
 118                        /* Hide some search errors */
 119                case -EACCES:
 120                case -ENOTDIR:
 121                case -EAGAIN:
 122                        return ERR_PTR(-ENOKEY);
 123                default:
 124                        return ERR_CAST(ref);
 125                }
 126        }
 127
 128        key = key_ref_to_ptr(ref);
 129        if (id && skid) {
 130                const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
 131                if (!kids->id[1]) {
 132                        pr_debug("issuer+serial match, but expected SKID missing\n");
 133                        goto reject;
 134                }
 135                if (!asymmetric_key_id_same(skid, kids->id[1])) {
 136                        pr_debug("issuer+serial match, but SKID does not\n");
 137                        goto reject;
 138                }
 139        }
 140        
 141        pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
 142        return key;
 143
 144reject:
 145        key_put(key);
 146        return ERR_PTR(-EKEYREJECTED);
 147}
 148EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
 149
 150/*
 151 * Set up the signature parameters in an X.509 certificate.  This involves
 152 * digesting the signed data and extracting the signature.
 153 */
 154int x509_get_sig_params(struct x509_certificate *cert)
 155{
 156        struct crypto_shash *tfm;
 157        struct shash_desc *desc;
 158        size_t digest_size, desc_size;
 159        void *digest;
 160        int ret;
 161
 162        pr_devel("==>%s()\n", __func__);
 163
 164        if (cert->unsupported_crypto)
 165                return -ENOPKG;
 166        if (cert->sig.s)
 167                return 0;
 168
 169        cert->sig.s = kmemdup(cert->raw_sig, cert->raw_sig_size,
 170                              GFP_KERNEL);
 171        if (!cert->sig.s)
 172                return -ENOMEM;
 173
 174        cert->sig.s_size = cert->raw_sig_size;
 175
 176        /* Allocate the hashing algorithm we're going to need and find out how
 177         * big the hash operational data will be.
 178         */
 179        tfm = crypto_alloc_shash(cert->sig.hash_algo, 0, 0);
 180        if (IS_ERR(tfm)) {
 181                if (PTR_ERR(tfm) == -ENOENT) {
 182                        cert->unsupported_crypto = true;
 183                        return -ENOPKG;
 184                }
 185                return PTR_ERR(tfm);
 186        }
 187
 188        desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
 189        digest_size = crypto_shash_digestsize(tfm);
 190
 191        /* We allocate the hash operational data storage on the end of the
 192         * digest storage space.
 193         */
 194        ret = -ENOMEM;
 195        digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size,
 196                         GFP_KERNEL);
 197        if (!digest)
 198                goto error;
 199
 200        cert->sig.digest = digest;
 201        cert->sig.digest_size = digest_size;
 202
 203        desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc));
 204        desc->tfm = tfm;
 205        desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
 206
 207        ret = crypto_shash_init(desc);
 208        if (ret < 0)
 209                goto error;
 210        might_sleep();
 211        ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest);
 212error:
 213        crypto_free_shash(tfm);
 214        pr_devel("<==%s() = %d\n", __func__, ret);
 215        return ret;
 216}
 217EXPORT_SYMBOL_GPL(x509_get_sig_params);
 218
 219/*
 220 * Check the signature on a certificate using the provided public key
 221 */
 222int x509_check_signature(const struct public_key *pub,
 223                         struct x509_certificate *cert)
 224{
 225        int ret;
 226
 227        pr_devel("==>%s()\n", __func__);
 228
 229        ret = x509_get_sig_params(cert);
 230        if (ret < 0)
 231                return ret;
 232
 233        ret = public_key_verify_signature(pub, &cert->sig);
 234        if (ret == -ENOPKG)
 235                cert->unsupported_crypto = true;
 236        pr_debug("Cert Verification: %d\n", ret);
 237        return ret;
 238}
 239EXPORT_SYMBOL_GPL(x509_check_signature);
 240
 241/*
 242 * Check the new certificate against the ones in the trust keyring.  If one of
 243 * those is the signing key and validates the new certificate, then mark the
 244 * new certificate as being trusted.
 245 *
 246 * Return 0 if the new certificate was successfully validated, 1 if we couldn't
 247 * find a matching parent certificate in the trusted list and an error if there
 248 * is a matching certificate but the signature check fails.
 249 */
 250static int x509_validate_trust(struct x509_certificate *cert,
 251                               struct key *trust_keyring)
 252{
 253        struct key *key;
 254        int ret = 1;
 255
 256        if (!trust_keyring)
 257                return -EOPNOTSUPP;
 258
 259        if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid))
 260                return -EPERM;
 261
 262        key = x509_request_asymmetric_key(trust_keyring,
 263                                          cert->akid_id, cert->akid_skid,
 264                                          false);
 265        if (!IS_ERR(key))  {
 266                if (!use_builtin_keys
 267                    || test_bit(KEY_FLAG_BUILTIN, &key->flags))
 268                        ret = x509_check_signature(key->payload.data[asym_crypto],
 269                                                   cert);
 270                key_put(key);
 271        }
 272        return ret;
 273}
 274
 275/*
 276 * Attempt to parse a data blob for a key as an X509 certificate.
 277 */
 278static int x509_key_preparse(struct key_preparsed_payload *prep)
 279{
 280        struct asymmetric_key_ids *kids;
 281        struct x509_certificate *cert;
 282        const char *q;
 283        size_t srlen, sulen;
 284        char *desc = NULL, *p;
 285        int ret;
 286
 287        cert = x509_cert_parse(prep->data, prep->datalen);
 288        if (IS_ERR(cert))
 289                return PTR_ERR(cert);
 290
 291        pr_devel("Cert Issuer: %s\n", cert->issuer);
 292        pr_devel("Cert Subject: %s\n", cert->subject);
 293
 294        if (!cert->pub->pkey_algo ||
 295            !cert->sig.pkey_algo ||
 296            !cert->sig.hash_algo) {
 297                ret = -ENOPKG;
 298                goto error_free_cert;
 299        }
 300
 301        pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo);
 302        pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to);
 303        pr_devel("Cert Signature: %s + %s\n",
 304                 cert->sig.pkey_algo,
 305                 cert->sig.hash_algo);
 306
 307        cert->pub->id_type = "X509";
 308
 309        /* Check the signature on the key if it appears to be self-signed */
 310        if ((!cert->akid_skid && !cert->akid_id) ||
 311            asymmetric_key_id_same(cert->skid, cert->akid_skid) ||
 312            asymmetric_key_id_same(cert->id, cert->akid_id)) {
 313                ret = x509_check_signature(cert->pub, cert); /* self-signed */
 314                if (ret < 0)
 315                        goto error_free_cert;
 316        } else if (!prep->trusted) {
 317                ret = x509_validate_trust(cert, get_system_trusted_keyring());
 318                if (ret)
 319                        ret = x509_validate_trust(cert, get_ima_mok_keyring());
 320                if (!ret)
 321                        prep->trusted = 1;
 322        }
 323
 324        /* Propose a description */
 325        sulen = strlen(cert->subject);
 326        if (cert->raw_skid) {
 327                srlen = cert->raw_skid_size;
 328                q = cert->raw_skid;
 329        } else {
 330                srlen = cert->raw_serial_size;
 331                q = cert->raw_serial;
 332        }
 333
 334        ret = -ENOMEM;
 335        desc = kmalloc(sulen + 2 + srlen * 2 + 1, GFP_KERNEL);
 336        if (!desc)
 337                goto error_free_cert;
 338        p = memcpy(desc, cert->subject, sulen);
 339        p += sulen;
 340        *p++ = ':';
 341        *p++ = ' ';
 342        p = bin2hex(p, q, srlen);
 343        *p = 0;
 344
 345        kids = kmalloc(sizeof(struct asymmetric_key_ids), GFP_KERNEL);
 346        if (!kids)
 347                goto error_free_desc;
 348        kids->id[0] = cert->id;
 349        kids->id[1] = cert->skid;
 350
 351        /* We're pinning the module by being linked against it */
 352        __module_get(public_key_subtype.owner);
 353        prep->payload.data[asym_subtype] = &public_key_subtype;
 354        prep->payload.data[asym_key_ids] = kids;
 355        prep->payload.data[asym_crypto] = cert->pub;
 356        prep->description = desc;
 357        prep->quotalen = 100;
 358
 359        /* We've finished with the certificate */
 360        cert->pub = NULL;
 361        cert->id = NULL;
 362        cert->skid = NULL;
 363        desc = NULL;
 364        ret = 0;
 365
 366error_free_desc:
 367        kfree(desc);
 368error_free_cert:
 369        x509_free_certificate(cert);
 370        return ret;
 371}
 372
 373static struct asymmetric_key_parser x509_key_parser = {
 374        .owner  = THIS_MODULE,
 375        .name   = "x509",
 376        .parse  = x509_key_preparse,
 377};
 378
 379/*
 380 * Module stuff
 381 */
 382static int __init x509_key_init(void)
 383{
 384        return register_asymmetric_key_parser(&x509_key_parser);
 385}
 386
 387static void __exit x509_key_exit(void)
 388{
 389        unregister_asymmetric_key_parser(&x509_key_parser);
 390}
 391
 392module_init(x509_key_init);
 393module_exit(x509_key_exit);
 394
 395MODULE_DESCRIPTION("X.509 certificate parser");
 396MODULE_LICENSE("GPL");
 397