linux/crypto/asymmetric_keys/asymmetric_type.c
<<
>>
Prefs
   1/* Asymmetric public-key cryptography key type
   2 *
   3 * See Documentation/security/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#include <keys/asymmetric-subtype.h>
  14#include <keys/asymmetric-parser.h>
  15#include <linux/seq_file.h>
  16#include <linux/module.h>
  17#include <linux/slab.h>
  18#include "asymmetric_keys.h"
  19
  20MODULE_LICENSE("GPL");
  21
  22static LIST_HEAD(asymmetric_key_parsers);
  23static DECLARE_RWSEM(asymmetric_key_parsers_sem);
  24
  25/*
  26 * Match asymmetric keys on (part of) their name
  27 * We have some shorthand methods for matching keys.  We allow:
  28 *
  29 *      "<desc>"        - request a key by description
  30 *      "id:<id>"       - request a key matching the ID
  31 *      "<subtype>:<id>" - request a key of a subtype
  32 */
  33static int asymmetric_key_match(const struct key *key, const void *description)
  34{
  35        const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
  36        const char *spec = description;
  37        const char *id, *kid;
  38        ptrdiff_t speclen;
  39        size_t idlen, kidlen;
  40
  41        if (!subtype || !spec || !*spec)
  42                return 0;
  43
  44        /* See if the full key description matches as is */
  45        if (key->description && strcmp(key->description, description) == 0)
  46                return 1;
  47
  48        /* All tests from here on break the criterion description into a
  49         * specifier, a colon and then an identifier.
  50         */
  51        id = strchr(spec, ':');
  52        if (!id)
  53                return 0;
  54
  55        speclen = id - spec;
  56        id++;
  57
  58        /* Anything after here requires a partial match on the ID string */
  59        kid = asymmetric_key_id(key);
  60        if (!kid)
  61                return 0;
  62
  63        idlen = strlen(id);
  64        kidlen = strlen(kid);
  65        if (idlen > kidlen)
  66                return 0;
  67
  68        kid += kidlen - idlen;
  69        if (strcasecmp(id, kid) != 0)
  70                return 0;
  71
  72        if (speclen == 2 &&
  73            memcmp(spec, "id", 2) == 0)
  74                return 1;
  75
  76        if (speclen == subtype->name_len &&
  77            memcmp(spec, subtype->name, speclen) == 0)
  78                return 1;
  79
  80        return 0;
  81}
  82
  83/*
  84 * Describe the asymmetric key
  85 */
  86static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
  87{
  88        const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
  89        const char *kid = asymmetric_key_id(key);
  90        size_t n;
  91
  92        seq_puts(m, key->description);
  93
  94        if (subtype) {
  95                seq_puts(m, ": ");
  96                subtype->describe(key, m);
  97
  98                if (kid) {
  99                        seq_putc(m, ' ');
 100                        n = strlen(kid);
 101                        if (n <= 8)
 102                                seq_puts(m, kid);
 103                        else
 104                                seq_puts(m, kid + n - 8);
 105                }
 106
 107                seq_puts(m, " [");
 108                /* put something here to indicate the key's capabilities */
 109                seq_putc(m, ']');
 110        }
 111}
 112
 113/*
 114 * Preparse a asymmetric payload to get format the contents appropriately for the
 115 * internal payload to cut down on the number of scans of the data performed.
 116 *
 117 * We also generate a proposed description from the contents of the key that
 118 * can be used to name the key if the user doesn't want to provide one.
 119 */
 120static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
 121{
 122        struct asymmetric_key_parser *parser;
 123        int ret;
 124
 125        pr_devel("==>%s()\n", __func__);
 126
 127        if (prep->datalen == 0)
 128                return -EINVAL;
 129
 130        down_read(&asymmetric_key_parsers_sem);
 131
 132        ret = -EBADMSG;
 133        list_for_each_entry(parser, &asymmetric_key_parsers, link) {
 134                pr_debug("Trying parser '%s'\n", parser->name);
 135
 136                ret = parser->parse(prep);
 137                if (ret != -EBADMSG) {
 138                        pr_debug("Parser recognised the format (ret %d)\n",
 139                                 ret);
 140                        break;
 141                }
 142        }
 143
 144        up_read(&asymmetric_key_parsers_sem);
 145        pr_devel("<==%s() = %d\n", __func__, ret);
 146        return ret;
 147}
 148
 149/*
 150 * Clean up the preparse data
 151 */
 152static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
 153{
 154        struct asymmetric_key_subtype *subtype = prep->type_data[0];
 155
 156        pr_devel("==>%s()\n", __func__);
 157
 158        if (subtype) {
 159                subtype->destroy(prep->payload);
 160                module_put(subtype->owner);
 161        }
 162        kfree(prep->type_data[1]);
 163        kfree(prep->description);
 164}
 165
 166/*
 167 * Instantiate a asymmetric_key defined key.  The key was preparsed, so we just
 168 * have to transfer the data here.
 169 */
 170static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
 171{
 172        int ret;
 173
 174        pr_devel("==>%s()\n", __func__);
 175
 176        ret = key_payload_reserve(key, prep->quotalen);
 177        if (ret == 0) {
 178                key->type_data.p[0] = prep->type_data[0];
 179                key->type_data.p[1] = prep->type_data[1];
 180                key->payload.data = prep->payload;
 181                prep->type_data[0] = NULL;
 182                prep->type_data[1] = NULL;
 183                prep->payload = NULL;
 184        }
 185        pr_devel("<==%s() = %d\n", __func__, ret);
 186        return ret;
 187}
 188
 189/*
 190 * dispose of the data dangling from the corpse of a asymmetric key
 191 */
 192static void asymmetric_key_destroy(struct key *key)
 193{
 194        struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
 195        if (subtype) {
 196                subtype->destroy(key->payload.data);
 197                module_put(subtype->owner);
 198                key->type_data.p[0] = NULL;
 199        }
 200        kfree(key->type_data.p[1]);
 201        key->type_data.p[1] = NULL;
 202}
 203
 204struct key_type key_type_asymmetric = {
 205        .name           = "asymmetric",
 206        .preparse       = asymmetric_key_preparse,
 207        .free_preparse  = asymmetric_key_free_preparse,
 208        .instantiate    = asymmetric_key_instantiate,
 209        .match          = asymmetric_key_match,
 210        .destroy        = asymmetric_key_destroy,
 211        .describe       = asymmetric_key_describe,
 212};
 213EXPORT_SYMBOL_GPL(key_type_asymmetric);
 214
 215/**
 216 * register_asymmetric_key_parser - Register a asymmetric key blob parser
 217 * @parser: The parser to register
 218 */
 219int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
 220{
 221        struct asymmetric_key_parser *cursor;
 222        int ret;
 223
 224        down_write(&asymmetric_key_parsers_sem);
 225
 226        list_for_each_entry(cursor, &asymmetric_key_parsers, link) {
 227                if (strcmp(cursor->name, parser->name) == 0) {
 228                        pr_err("Asymmetric key parser '%s' already registered\n",
 229                               parser->name);
 230                        ret = -EEXIST;
 231                        goto out;
 232                }
 233        }
 234
 235        list_add_tail(&parser->link, &asymmetric_key_parsers);
 236
 237        pr_notice("Asymmetric key parser '%s' registered\n", parser->name);
 238        ret = 0;
 239
 240out:
 241        up_write(&asymmetric_key_parsers_sem);
 242        return ret;
 243}
 244EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
 245
 246/**
 247 * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
 248 * @parser: The parser to unregister
 249 */
 250void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
 251{
 252        down_write(&asymmetric_key_parsers_sem);
 253        list_del(&parser->link);
 254        up_write(&asymmetric_key_parsers_sem);
 255
 256        pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name);
 257}
 258EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
 259
 260/*
 261 * Module stuff
 262 */
 263static int __init asymmetric_key_init(void)
 264{
 265        return register_key_type(&key_type_asymmetric);
 266}
 267
 268static void __exit asymmetric_key_cleanup(void)
 269{
 270        unregister_key_type(&key_type_asymmetric);
 271}
 272
 273module_init(asymmetric_key_init);
 274module_exit(asymmetric_key_cleanup);
 275