Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[CRYPTO] gcm: Allow block cipher parameter

This patch adds the gcm_base template which takes a block cipher
parameter instead of cipher. This allows the user to specify a
specific CTR implementation.

This also fixes a leak of the cipher algorithm that was previously
looked up but never freed.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

+89 -24
+89 -24
crypto/gcm.c
··· 413 413 crypto_free_ablkcipher(ctx->ctr); 414 414 } 415 415 416 - static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb) 416 + static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb, 417 + const char *full_name, 418 + const char *ctr_name) 417 419 { 420 + struct crypto_attr_type *algt; 418 421 struct crypto_instance *inst; 419 422 struct crypto_alg *ctr; 420 - struct crypto_alg *cipher; 421 423 struct gcm_instance_ctx *ctx; 422 424 int err; 423 - char ctr_name[CRYPTO_MAX_ALG_NAME]; 424 425 425 - err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD); 426 - if (err) 426 + algt = crypto_get_attr_type(tb); 427 + err = PTR_ERR(algt); 428 + if (IS_ERR(algt)) 427 429 return ERR_PTR(err); 428 430 429 - cipher = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER, 430 - CRYPTO_ALG_TYPE_MASK); 431 - 432 - inst = ERR_PTR(PTR_ERR(cipher)); 433 - if (IS_ERR(cipher)) 434 - return inst; 435 - 436 - inst = ERR_PTR(ENAMETOOLONG); 437 - if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", 438 - cipher->cra_name) >= CRYPTO_MAX_ALG_NAME) 439 - return inst; 431 + if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) 432 + return ERR_PTR(-EINVAL); 440 433 441 434 ctr = crypto_alg_mod_lookup(ctr_name, CRYPTO_ALG_TYPE_BLKCIPHER, 442 435 CRYPTO_ALG_TYPE_MASK); ··· 437 444 if (IS_ERR(ctr)) 438 445 return ERR_PTR(PTR_ERR(ctr)); 439 446 440 - if (cipher->cra_blocksize != 16) 447 + /* We only support 16-byte blocks. */ 448 + if ((ctr->cra_type == &crypto_blkcipher_type ? 449 + ctr->cra_blkcipher.ivsize : ctr->cra_ablkcipher.ivsize) != 16) 450 + goto out_put_ctr; 451 + 452 + /* Not a stream cipher? */ 453 + err = -EINVAL; 454 + if (ctr->cra_blocksize != 1) 441 455 goto out_put_ctr; 442 456 443 457 inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); ··· 453 453 goto out_put_ctr; 454 454 455 455 err = -ENAMETOOLONG; 456 - if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, 457 - "gcm(%s)", cipher->cra_name) >= CRYPTO_MAX_ALG_NAME || 458 - snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, 459 - "gcm(%s)", cipher->cra_driver_name) >= CRYPTO_MAX_ALG_NAME) 456 + if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, 457 + "gcm_base(%s)", ctr->cra_driver_name) >= 458 + CRYPTO_MAX_ALG_NAME) 460 459 goto err_free_inst; 461 - 462 460 463 461 ctx = crypto_instance_ctx(inst); 464 462 err = crypto_init_spawn(&ctx->ctr, ctr, inst, CRYPTO_ALG_TYPE_MASK); 465 463 if (err) 466 464 goto err_free_inst; 467 465 466 + memcpy(inst->alg.cra_name, full_name, CRYPTO_MAX_ALG_NAME); 467 + 468 468 inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC; 469 469 inst->alg.cra_priority = ctr->cra_priority; 470 - inst->alg.cra_blocksize = 16; 470 + inst->alg.cra_blocksize = 1; 471 471 inst->alg.cra_alignmask = ctr->cra_alignmask | (__alignof__(u64) - 1); 472 472 inst->alg.cra_type = &crypto_aead_type; 473 473 inst->alg.cra_aead.ivsize = 16; ··· 489 489 goto out; 490 490 } 491 491 492 + static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb) 493 + { 494 + int err; 495 + const char *cipher_name; 496 + char ctr_name[CRYPTO_MAX_ALG_NAME]; 497 + char full_name[CRYPTO_MAX_ALG_NAME]; 498 + 499 + cipher_name = crypto_attr_alg_name(tb[1]); 500 + err = PTR_ERR(cipher_name); 501 + if (IS_ERR(cipher_name)) 502 + return ERR_PTR(err); 503 + 504 + if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", cipher_name) >= 505 + CRYPTO_MAX_ALG_NAME) 506 + return ERR_PTR(-ENAMETOOLONG); 507 + 508 + if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm(%s)", cipher_name) >= 509 + CRYPTO_MAX_ALG_NAME) 510 + return ERR_PTR(-ENAMETOOLONG); 511 + 512 + return crypto_gcm_alloc_common(tb, full_name, ctr_name); 513 + } 514 + 492 515 static void crypto_gcm_free(struct crypto_instance *inst) 493 516 { 494 517 struct gcm_instance_ctx *ctx = crypto_instance_ctx(inst); ··· 527 504 .module = THIS_MODULE, 528 505 }; 529 506 507 + static struct crypto_instance *crypto_gcm_base_alloc(struct rtattr **tb) 508 + { 509 + int err; 510 + const char *ctr_name; 511 + char full_name[CRYPTO_MAX_ALG_NAME]; 512 + 513 + ctr_name = crypto_attr_alg_name(tb[1]); 514 + err = PTR_ERR(ctr_name); 515 + if (IS_ERR(ctr_name)) 516 + return ERR_PTR(err); 517 + 518 + if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s)", 519 + ctr_name) >= CRYPTO_MAX_ALG_NAME) 520 + return ERR_PTR(-ENAMETOOLONG); 521 + 522 + return crypto_gcm_alloc_common(tb, full_name, ctr_name); 523 + } 524 + 525 + static struct crypto_template crypto_gcm_base_tmpl = { 526 + .name = "gcm_base", 527 + .alloc = crypto_gcm_base_alloc, 528 + .free = crypto_gcm_free, 529 + .module = THIS_MODULE, 530 + }; 531 + 530 532 static int __init crypto_gcm_module_init(void) 531 533 { 532 - return crypto_register_template(&crypto_gcm_tmpl); 534 + int err; 535 + 536 + err = crypto_register_template(&crypto_gcm_base_tmpl); 537 + if (err) 538 + goto out; 539 + 540 + err = crypto_register_template(&crypto_gcm_tmpl); 541 + if (err) 542 + goto out_undo_base; 543 + 544 + out: 545 + return err; 546 + 547 + out_undo_base: 548 + crypto_unregister_template(&crypto_gcm_base_tmpl); 549 + goto out; 533 550 } 534 551 535 552 static void __exit crypto_gcm_module_exit(void) 536 553 { 537 554 crypto_unregister_template(&crypto_gcm_tmpl); 555 + crypto_unregister_template(&crypto_gcm_base_tmpl); 538 556 } 539 557 540 558 module_init(crypto_gcm_module_init); ··· 584 520 MODULE_LICENSE("GPL"); 585 521 MODULE_DESCRIPTION("Galois/Counter Mode"); 586 522 MODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>"); 523 + MODULE_ALIAS("gcm_base");