linux/crypto/algapi.c
<<
>>
Prefs
   1/*
   2 * Cryptographic API for algorithms (i.e., low-level API).
   3 *
   4 * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms of the GNU General Public License as published by the Free
   8 * Software Foundation; either version 2 of the License, or (at your option)
   9 * any later version.
  10 *
  11 */
  12
  13#include <linux/err.h>
  14#include <linux/errno.h>
  15#include <linux/init.h>
  16#include <linux/kernel.h>
  17#include <linux/list.h>
  18#include <linux/module.h>
  19#include <linux/rtnetlink.h>
  20#include <linux/string.h>
  21
  22#include "internal.h"
  23
  24static LIST_HEAD(crypto_template_list);
  25
  26void crypto_larval_error(const char *name, u32 type, u32 mask)
  27{
  28        struct crypto_alg *alg;
  29
  30        down_read(&crypto_alg_sem);
  31        alg = __crypto_alg_lookup(name, type, mask);
  32        up_read(&crypto_alg_sem);
  33
  34        if (alg) {
  35                if (crypto_is_larval(alg)) {
  36                        struct crypto_larval *larval = (void *)alg;
  37                        complete(&larval->completion);
  38                }
  39                crypto_mod_put(alg);
  40        }
  41}
  42EXPORT_SYMBOL_GPL(crypto_larval_error);
  43
  44static inline int crypto_set_driver_name(struct crypto_alg *alg)
  45{
  46        static const char suffix[] = "-generic";
  47        char *driver_name = alg->cra_driver_name;
  48        int len;
  49
  50        if (*driver_name)
  51                return 0;
  52
  53        len = strlcpy(driver_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
  54        if (len + sizeof(suffix) > CRYPTO_MAX_ALG_NAME)
  55                return -ENAMETOOLONG;
  56
  57        memcpy(driver_name + len, suffix, sizeof(suffix));
  58        return 0;
  59}
  60
  61static int crypto_check_alg(struct crypto_alg *alg)
  62{
  63        if (alg->cra_alignmask & (alg->cra_alignmask + 1))
  64                return -EINVAL;
  65
  66        if (alg->cra_alignmask & alg->cra_blocksize)
  67                return -EINVAL;
  68
  69        if (alg->cra_blocksize > PAGE_SIZE / 8)
  70                return -EINVAL;
  71
  72        if (alg->cra_priority < 0)
  73                return -EINVAL;
  74
  75        return crypto_set_driver_name(alg);
  76}
  77
  78static void crypto_destroy_instance(struct crypto_alg *alg)
  79{
  80        struct crypto_instance *inst = (void *)alg;
  81        struct crypto_template *tmpl = inst->tmpl;
  82
  83        tmpl->free(inst);
  84        crypto_tmpl_put(tmpl);
  85}
  86
  87static void crypto_remove_spawns(struct list_head *spawns,
  88                                 struct list_head *list)
  89{
  90        struct crypto_spawn *spawn, *n;
  91
  92        list_for_each_entry_safe(spawn, n, spawns, list) {
  93                struct crypto_instance *inst = spawn->inst;
  94                struct crypto_template *tmpl = inst->tmpl;
  95
  96                list_del_init(&spawn->list);
  97                spawn->alg = NULL;
  98
  99                if (crypto_is_dead(&inst->alg))
 100                        continue;
 101
 102                inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
 103                if (!tmpl || !crypto_tmpl_get(tmpl))
 104                        continue;
 105
 106                crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
 107                list_move(&inst->alg.cra_list, list);
 108                hlist_del(&inst->list);
 109                inst->alg.cra_destroy = crypto_destroy_instance;
 110
 111                if (!list_empty(&inst->alg.cra_users)) {
 112                        if (&n->list == spawns)
 113                                n = list_entry(inst->alg.cra_users.next,
 114                                               typeof(*n), list);
 115                        __list_splice(&inst->alg.cra_users, spawns->prev);
 116                }
 117        }
 118}
 119
 120static int __crypto_register_alg(struct crypto_alg *alg,
 121                                 struct list_head *list)
 122{
 123        struct crypto_alg *q;
 124        int ret = -EAGAIN;
 125
 126        if (crypto_is_dead(alg))
 127                goto out;
 128
 129        INIT_LIST_HEAD(&alg->cra_users);
 130
 131        ret = -EEXIST;
 132
 133        atomic_set(&alg->cra_refcnt, 1);
 134        list_for_each_entry(q, &crypto_alg_list, cra_list) {
 135                if (q == alg)
 136                        goto out;
 137
 138                if (crypto_is_moribund(q))
 139                        continue;
 140
 141                if (crypto_is_larval(q)) {
 142                        struct crypto_larval *larval = (void *)q;
 143
 144                        if (strcmp(alg->cra_name, q->cra_name) &&
 145                            strcmp(alg->cra_driver_name, q->cra_name))
 146                                continue;
 147
 148                        if (larval->adult)
 149                                continue;
 150                        if ((q->cra_flags ^ alg->cra_flags) & larval->mask)
 151                                continue;
 152                        if (!crypto_mod_get(alg))
 153                                continue;
 154
 155                        larval->adult = alg;
 156                        complete(&larval->completion);
 157                        continue;
 158                }
 159
 160                if (strcmp(alg->cra_name, q->cra_name))
 161                        continue;
 162
 163                if (strcmp(alg->cra_driver_name, q->cra_driver_name) &&
 164                    q->cra_priority > alg->cra_priority)
 165                        continue;
 166
 167                crypto_remove_spawns(&q->cra_users, list);
 168        }
 169        
 170        list_add(&alg->cra_list, &crypto_alg_list);
 171
 172        crypto_notify(CRYPTO_MSG_ALG_REGISTER, alg);
 173        ret = 0;
 174
 175out:    
 176        return ret;
 177}
 178
 179static void crypto_remove_final(struct list_head *list)
 180{
 181        struct crypto_alg *alg;
 182        struct crypto_alg *n;
 183
 184        list_for_each_entry_safe(alg, n, list, cra_list) {
 185                list_del_init(&alg->cra_list);
 186                crypto_alg_put(alg);
 187        }
 188}
 189
 190int crypto_register_alg(struct crypto_alg *alg)
 191{
 192        LIST_HEAD(list);
 193        int err;
 194
 195        err = crypto_check_alg(alg);
 196        if (err)
 197                return err;
 198
 199        down_write(&crypto_alg_sem);
 200        err = __crypto_register_alg(alg, &list);
 201        up_write(&crypto_alg_sem);
 202
 203        crypto_remove_final(&list);
 204        return err;
 205}
 206EXPORT_SYMBOL_GPL(crypto_register_alg);
 207
 208static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
 209{
 210        if (unlikely(list_empty(&alg->cra_list)))
 211                return -ENOENT;
 212
 213        alg->cra_flags |= CRYPTO_ALG_DEAD;
 214
 215        crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
 216        list_del_init(&alg->cra_list);
 217        crypto_remove_spawns(&alg->cra_users, list);
 218
 219        return 0;
 220}
 221
 222int crypto_unregister_alg(struct crypto_alg *alg)
 223{
 224        int ret;
 225        LIST_HEAD(list);
 226        
 227        down_write(&crypto_alg_sem);
 228        ret = crypto_remove_alg(alg, &list);
 229        up_write(&crypto_alg_sem);
 230
 231        if (ret)
 232                return ret;
 233
 234        BUG_ON(atomic_read(&alg->cra_refcnt) != 1);
 235        if (alg->cra_destroy)
 236                alg->cra_destroy(alg);
 237
 238        crypto_remove_final(&list);
 239        return 0;
 240}
 241EXPORT_SYMBOL_GPL(crypto_unregister_alg);
 242
 243int crypto_register_template(struct crypto_template *tmpl)
 244{
 245        struct crypto_template *q;
 246        int err = -EEXIST;
 247
 248        down_write(&crypto_alg_sem);
 249
 250        list_for_each_entry(q, &crypto_template_list, list) {
 251                if (q == tmpl)
 252                        goto out;
 253        }
 254
 255        list_add(&tmpl->list, &crypto_template_list);
 256        crypto_notify(CRYPTO_MSG_TMPL_REGISTER, tmpl);
 257        err = 0;
 258out:
 259        up_write(&crypto_alg_sem);
 260        return err;
 261}
 262EXPORT_SYMBOL_GPL(crypto_register_template);
 263
 264void crypto_unregister_template(struct crypto_template *tmpl)
 265{
 266        struct crypto_instance *inst;
 267        struct hlist_node *p, *n;
 268        struct hlist_head *list;
 269        LIST_HEAD(users);
 270
 271        down_write(&crypto_alg_sem);
 272
 273        BUG_ON(list_empty(&tmpl->list));
 274        list_del_init(&tmpl->list);
 275
 276        list = &tmpl->instances;
 277        hlist_for_each_entry(inst, p, list, list) {
 278                int err = crypto_remove_alg(&inst->alg, &users);
 279                BUG_ON(err);
 280        }
 281
 282        crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl);
 283
 284        up_write(&crypto_alg_sem);
 285
 286        hlist_for_each_entry_safe(inst, p, n, list, list) {
 287                BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1);
 288                tmpl->free(inst);
 289        }
 290        crypto_remove_final(&users);
 291}
 292EXPORT_SYMBOL_GPL(crypto_unregister_template);
 293
 294static struct crypto_template *__crypto_lookup_template(const char *name)
 295{
 296        struct crypto_template *q, *tmpl = NULL;
 297
 298        down_read(&crypto_alg_sem);
 299        list_for_each_entry(q, &crypto_template_list, list) {
 300                if (strcmp(q->name, name))
 301                        continue;
 302                if (unlikely(!crypto_tmpl_get(q)))
 303                        continue;
 304
 305                tmpl = q;
 306                break;
 307        }
 308        up_read(&crypto_alg_sem);
 309
 310        return tmpl;
 311}
 312
 313struct crypto_template *crypto_lookup_template(const char *name)
 314{
 315        return try_then_request_module(__crypto_lookup_template(name), name);
 316}
 317EXPORT_SYMBOL_GPL(crypto_lookup_template);
 318
 319int crypto_register_instance(struct crypto_template *tmpl,
 320                             struct crypto_instance *inst)
 321{
 322        LIST_HEAD(list);
 323        int err = -EINVAL;
 324
 325        if (inst->alg.cra_destroy)
 326                goto err;
 327
 328        err = crypto_check_alg(&inst->alg);
 329        if (err)
 330                goto err;
 331
 332        inst->alg.cra_module = tmpl->module;
 333
 334        down_write(&crypto_alg_sem);
 335
 336        err = __crypto_register_alg(&inst->alg, &list);
 337        if (err)
 338                goto unlock;
 339
 340        hlist_add_head(&inst->list, &tmpl->instances);
 341        inst->tmpl = tmpl;
 342
 343unlock:
 344        up_write(&crypto_alg_sem);
 345
 346        crypto_remove_final(&list);
 347
 348err:
 349        return err;
 350}
 351EXPORT_SYMBOL_GPL(crypto_register_instance);
 352
 353int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
 354                      struct crypto_instance *inst)
 355{
 356        int err = -EAGAIN;
 357
 358        spawn->inst = inst;
 359
 360        down_write(&crypto_alg_sem);
 361        if (!crypto_is_moribund(alg)) {
 362                list_add(&spawn->list, &alg->cra_users);
 363                spawn->alg = alg;
 364                err = 0;
 365        }
 366        up_write(&crypto_alg_sem);
 367
 368        return err;
 369}
 370EXPORT_SYMBOL_GPL(crypto_init_spawn);
 371
 372void crypto_drop_spawn(struct crypto_spawn *spawn)
 373{
 374        down_write(&crypto_alg_sem);
 375        list_del(&spawn->list);
 376        up_write(&crypto_alg_sem);
 377}
 378EXPORT_SYMBOL_GPL(crypto_drop_spawn);
 379
 380struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn)
 381{
 382        struct crypto_alg *alg;
 383        struct crypto_alg *alg2;
 384        struct crypto_tfm *tfm;
 385
 386        down_read(&crypto_alg_sem);
 387        alg = spawn->alg;
 388        alg2 = alg;
 389        if (alg2)
 390                alg2 = crypto_mod_get(alg2);
 391        up_read(&crypto_alg_sem);
 392
 393        if (!alg2) {
 394                if (alg)
 395                        crypto_shoot_alg(alg);
 396                return ERR_PTR(-EAGAIN);
 397        }
 398
 399        tfm = __crypto_alloc_tfm(alg, 0);
 400        if (IS_ERR(tfm))
 401                crypto_mod_put(alg);
 402
 403        return tfm;
 404}
 405EXPORT_SYMBOL_GPL(crypto_spawn_tfm);
 406
 407int crypto_register_notifier(struct notifier_block *nb)
 408{
 409        return blocking_notifier_chain_register(&crypto_chain, nb);
 410}
 411EXPORT_SYMBOL_GPL(crypto_register_notifier);
 412
 413int crypto_unregister_notifier(struct notifier_block *nb)
 414{
 415        return blocking_notifier_chain_unregister(&crypto_chain, nb);
 416}
 417EXPORT_SYMBOL_GPL(crypto_unregister_notifier);
 418
 419struct crypto_alg *crypto_get_attr_alg(void *param, unsigned int len,
 420                                       u32 type, u32 mask)
 421{
 422        struct rtattr *rta = param;
 423        struct crypto_attr_alg *alga;
 424
 425        if (!RTA_OK(rta, len))
 426                return ERR_PTR(-EBADR);
 427        if (rta->rta_type != CRYPTOA_ALG || RTA_PAYLOAD(rta) < sizeof(*alga))
 428                return ERR_PTR(-EINVAL);
 429
 430        alga = RTA_DATA(rta);
 431        alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0;
 432
 433        return crypto_alg_mod_lookup(alga->name, type, mask);
 434}
 435EXPORT_SYMBOL_GPL(crypto_get_attr_alg);
 436
 437struct crypto_instance *crypto_alloc_instance(const char *name,
 438                                              struct crypto_alg *alg)
 439{
 440        struct crypto_instance *inst;
 441        struct crypto_spawn *spawn;
 442        int err;
 443
 444        inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
 445        if (!inst)
 446                return ERR_PTR(-ENOMEM);
 447
 448        err = -ENAMETOOLONG;
 449        if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", name,
 450                     alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
 451                goto err_free_inst;
 452
 453        if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
 454                     name, alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
 455                goto err_free_inst;
 456
 457        spawn = crypto_instance_ctx(inst);
 458        err = crypto_init_spawn(spawn, alg, inst);
 459
 460        if (err)
 461                goto err_free_inst;
 462
 463        return inst;
 464
 465err_free_inst:
 466        kfree(inst);
 467        return ERR_PTR(err);
 468}
 469EXPORT_SYMBOL_GPL(crypto_alloc_instance);
 470
 471static int __init crypto_algapi_init(void)
 472{
 473        crypto_init_proc();
 474        return 0;
 475}
 476
 477static void __exit crypto_algapi_exit(void)
 478{
 479        crypto_exit_proc();
 480}
 481
 482module_init(crypto_algapi_init);
 483module_exit(crypto_algapi_exit);
 484
 485MODULE_LICENSE("GPL");
 486MODULE_DESCRIPTION("Cryptographic algorithms API");
 487
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.